XAML User Control Base Element Type - xaml

In XAML, you can create your own reusable control type as a UserControl object like this:
<UserControl x:Class="MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Grid>
<Button Content="Test"/>
</Grid>
</UserControl>
But you can also just change the base type in that view to be the same type as the content container like this:
<Grid x:Class="MyControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<Button Content="Test"/>
</Grid>
What is the difference between these two options? In my example, they both derive from FrameworkElement and diverge in inheritance from there. But it seems like they function the same.
I'm sure there's a good reason for one versus the other, but I'm having trouble coming up with a good scenario to justify the distinction. Can anyone enlighten me?

Honestly, the main reason for having different base types is properties.
If you find that a UserControl doesn't have the dependency properties you need - perhaps you'd like it to expand some content from time to time, then you could base it on an Expander rather than going into the code-behind to type 'propdp' and reinvent the wheel, replace the template instead of just stuffing things into the "content" property and bind to the Expander's "IsExpanded" property.
Doing this allows you to blur the line between UserControl and Custom Control by essentially making a copy of the template of an existing control and adding to it; taking advantage of existing properties and adding new ones in code behind if needed.
The UserControl tag itself is just an average base, but if you feel something else is more fitting to what you want the control to be, then use that.
Or, if all you want is a glorified container to lob a bunch of textboxes or something in that will be frequently used, then you needn't change a thing.

Related

Binding in ListView in XAML Xamarin

Could someone answer me the question about listview?
I have variable MyDatas which is collection of listview (and it works):
<ListView
x:Name="lstView"
HasUnevenRows="True"
ItemsSource="{Binding MyDatas}"> ...
Next I have (part of my code but is enough for explaining the problem):
<Label Grid.Row="0"
Grid.Column="1"
Text="{Binding E1}"
FontSize="{Binding FProp.Size1}"
FontAttributes="{Binding FProp.Atrib1}"/>
E1 is a field of MyDatas and this binding works correct. I have property of fonts in another variable FProp (FProp.Size1 and FProp.Atrib1) and this is problem! How can I use this another variable in this listview?
If FProp is used outside of listview all is ok, if I use it in listview it does not work.
Thank you for help
I believe you are not binding correctly the font size.
You are referencing a property named Size1 inside the object FProp which is not in your current binding context. The main problem is that you can only have one binding context per object. So, you should include the Size1 and Atrib1in your MyDatas object in order to make it available for the label. Another option is to change the binding context of the listview to point to FProp then you could access the values on the labels, but you will lose access to the E1 value. So you will need to choose how to fix this problem depending on the options provided.
You could add an x:Name to your ListView, let's say listView1 and use something like this
{Binding Path=BindingContext.FProp.Size1, Source={x:Reference listView1}}

RichEditBox text wrapping UWP

I am trying to get a RichEditBox to take over the entire width of the app window and to be responsive to window resizing, so far the code I have is the following:
<RichEditBox HorizontalAlignment="Stretch"
TextWrapping="WrapWholeWords"
Height="250"
Name="Intro"/>
What I am getting from the code above is this:
Any ideas on how can I get this to work? Why is it that I tell the text to wrap and it doesn't follow?
UPDATE
I also tried this:
<RichEditBox HorizontalAlignment="Stretch"
Height="250"
Name="Intro"/>
But the result is:
The problem that I am having is that it seems that HorizontalAlignment="Stretch" does not really do anything. The only way I am able to set a decent width is by hard-coding it, for example: Width="600". But if I do this my UI will not respond correctly to resizing. I also tried HorizontalContentAlingment="Stretch" but the result is exactly the same.
How can I get my RichEditBox take up all the available Width and Wrap at the same time?
If you look at the documentation of RichEditBox.TextWrapping, you'll notice that WrapWholeWords is invalid. You have to use
<RichEditBox TextWrapping="Wrap"/>
-or-
<RichEditBox TextWrapping="NoWrap"/>
Since Wrap is the default value, you can drop the property.
<RichEditBox HorizontalAlignment="Stretch"
Height="250"
Name="Intro"/>
Edit: in reply to the updated question:
A control only takes the width of it's parent control. Some container controls (e.g. Grid) automatically take the full width available, while others (e.g. StackPanel) only take the required size of it's children. Using HorizontalAlignment="Stretch" in combination with a StackPanel as a parent control, will only use the MinWidth property instead of the full available width on your screen. Sometimes you can't directly see this issue, e.g. when your control is inside an itemtemplate of a ListView. Use the Live Visual Tree in Visual Studio to find the parent containers and locate the issue.
So in short: make sure your RichEditBox is inside a Grid (or similar control) instead of a StackPanel.

Change the source file of User Control

My problem is that I have class library where some user control is defined. I have several projects that use this library. In one of these projects I need to change layout of control. Is it possible to redefine Xaml file in Application project to change layout of the user control ?
May I suggest that you are approaching this problem with the wrong solution? First, I acknowledge that what you are wanting is technically possible. In fact, you could generate your XAML at runtime if you wanted - and make it endlessly dynamic. But that's so complicated when the solution could be so simple.
Visual States
A visual state lets you define the layout of a control or group of controls. Then, it let's you define another layout of a control or group of controls. And, then, again. When your control should look one way for Landscape, you change the state. When your control should look one way for Portrait, you change the state. And, when your control should look a totally different way for a certain app that is consuming it, you just switch the state.
This solution gives you the full design-time support provided through the XAML tooling. It is also aligned with the way XAML was intended to be used. And, it's the simplest. I think it is, at least.
Read this: http://blog.jerrynixon.com/2013/11/windows-81-how-to-use-visual-states-in.html
You just need to set the Width and the Height of the root element(layout) of the UserControl to Auto in its Xaml File, then, you can edit its height and width from your application project as you desire.
Here's a thread about how to set the size of the user control in DesignTime, this may clarify things to you as well.
http://lfhck.com/question/157908/wpf-usercontrol-design-time-size
You can achieve that by naming your controls/elements than accessing them from the application project, this example is in WPF but it would be the same in WinRT:
MainWindow.Xaml :
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:wpfApplication1="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<Grid>
<wpfApplication1:UserControl1 x:Name="UserControl1"></wpfApplication1:UserControl1>
</Grid>
</Window>
UserControl.Xaml :
<UserControl x:Class="WpfApplication1.UserControl1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="MainGrid">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"></ColumnDefinition>
<ColumnDefinition Width="*"></ColumnDefinition>
</Grid.ColumnDefinitions>
<Button x:Name="button">button in user control</Button>
</Grid>
</UserControl>
MainWindow.cs
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
Grid.SetColumn(UserControl1.button,1);
}
}
When you run this example the button will figure in the second collumn of the MainGrid.
Notice that I'm changing the layout from CodeBehind, if you still want to make changes directly from Xaml in the Application Project, you should create Properties
in the UserControl and make some binding stuff.

Referencing an item in a VirtualizingStackPanel

I'm playing with the "Grid Application," which is a C++ Metro app template provided by VS11. The main display is a collection of items displayed in a VirtualizingStackPanel:
<ScrollViewer x:name="itemGridScrollViewer">
<GridView x:name="itemGridView">
<GridView.ItemsPanel>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</GridView.ItemsPanel>
</GridView>
</ScrollViewer>
The actual items are displayed using the Standard250x250ItemTemplate data template defined in StandardStyles.xaml. One of the display elements of this is a graphic.
I'm trying to understand how to reference a specific item so that I can change the graphic at runtime. The ScrollViewer and the GridView have objects associated with them, so I can get to those, but I don't see how to get from there to the individual items.
All this stuff is completely new to me, so be gentle. :)
In general it's not a good idea to dig down into individual templated items in an ItemsControl because not only is it a pain, but that ItemTemplate can regenerate at different times (paging during virtualization, source collection updates, etc) and you'll be left holding an outdated UIElement that's no longer being displayed.
A better approach is to pull the data you need into the item data and in the ItemTemplate use Data Binding to make whatever changes you need to differentiate the UI. One option is to use an IValueConverter to get a different image depending on some state in the item data:
<GridView>
<GridView.ItemTemplate>
<DataTemplate>
<Image Source="{Binding Path=DataState, Converter={StaticResource MyStateToImageConverter}}"/>
</DataTemplate>
</GridView.ItemTemplate>
</GridView>
Here I'm assuming that the converter code has been written and an instance of the converter has already been declared as a resource (see here). You could alternatively do a direct Binding to a property on each item's data that specifies its image and skip the converter part.

Access a nested UserControl's ContentPresenter with Blend

I've created a simple UserControl in Blend which contains (amongst other things) a ContentPresenter.
I'd like to be able to drop this UserControl onto another UserControl and then add other controls into its ContentPresenter, but when I include it in the second UserControl I can't see a way to do this.
Using Blend, how do I expose the underlying ContentPresenter so that its contents can be set visually (ie: so they appear as child controls in the Objects and Timeline window)?
If it’s a content control, to add child controls you set them as the content of the control
<MyContentControl>
<Grid x:Name=”ImAChild”>
</Grid>
</MyContentControl>
Edit: now that I think about it you might need to do something to make the Content property the default property which is populated by the inner xaml of your control, I can't remember exactly what it was but if your xaml looks like this (below) it doesn't matter anyway
<MyContentControl>
<MyContentControl.Content>
<Grid x:Name=”ImAChild”>
</Grid>
</MyContentControl.Content>
</MyContentControl>
Edit2
Your MyUserControl would need a MyContent property of type object and it'd have to somehow display the value of that property. You might be able to create it in the setter of the MyContent property but it seems "hacky"
<MyUserControl>
<MyUserControl.MyContent>
<Grid x:Name=”ImAChild”>
</Grid>
</MyContentControl.MyContent>
</MyUserControl>