When starting to work with WPF UserControls, I stumbled upon several ways to bind content of a UserControl to one of its properties.
Here's example C# code for my control:
public sealed partial class MyUserControl : UserControl
{
public MyUserControl()
{
InitializeComponent();
}
public static readonly DependencyProperty TheTextProperty =
DependencyProperty.Register("TheText",
typeof (string),
typeof(MyUserControl),
new FrameworkPropertyMetadata(0,
FrameworkPropertyMetadataOptions.
BindsTwoWayByDefault)
);
public string TheText
{
get { return (string)GetValue(TheTextProperty); }
set { SetValue(TheTextProperty, value); }
}
}
And here are the different ways I found to bind content to this property:
<UserControl x:Class="MyUserControl"
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">
<StackPanel>
<TextBox Text="{Binding TheText,
RelativeSource={RelativeSource
AncestorType={x:Type UserControl}}}" />
</StackPanel>
</UserControl>
<UserControl x:Class="MyUserControl"
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">
<StackPanel DataContext="{Binding
RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}">
<TextBox Text="{Binding TheText}" />
</StackPanel>
</UserControl>
<UserControl x:Class="MyUserControl"
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">
<StackPanel x:Name="VisualTreeRoot">
<TextBox Text="{Binding TheText}" />
</StackPanel>
</UserControl>
Here's the constructor:
public MyUserControl()
{
InitializeComponent();
VisualTreeRoot.DataContext = this;
}
The first time I wanted to bind content of a UserControl to one of its properties, I though "hey, let's just set the DataContext of the UserControl directly to itself":
<UserControl x:Class="MyUserControl"
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"
DataContext="{Binding RelativeSource={RelativeSource Self}}">
Or:
public MyUserControl()
{
InitializeComponent();
this.DataContext = this;
}
However, this does not work if a user of the UserControl wants to bind its properties to other binding sources. The UserControl needs to inherit the DataContext from its parent to make this work. By overwriting it as presented above, the bindings won't find their sources anymore.
My final questions:
What are the advantages and disadvantages of each of the presented methods? When should you use which method? Are there more methods? 解决方案
Well in the first case there is no DataContext
for the TextBox
set to any of it's Parent's. Hence you're having to tell the TextBox
where in the VisualTree is the control with that property directly on it.
Second case DataContext
is set on StackPanel
which the TextBox
inherit's accordingly. This is better than approach one if you have multiple control's in the StackPanel
Setting DataContext
on the UserControl
itself is not always wrong(via constructor or xaml). I say this because if you have 20 control's out of which 15 that need to use properties defined in it's current UserControl
class and 5 that need's the parent of the UserControl
's DataContext
, You can always use a RelativeSource FindAncestor
binding on the minority.
Only "method" I can think of that can show pt3 I mentioned is something like
<!-- Can change type to another userControl too and specify Ancestorlevel -->
<TextBlock Text="{Binding TheText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
^^ This will work fine even if the TextBlock
's parent UserControl
has itself as it's DataContext
As far as when to use what.
That's just a logical choice, if you have multiple siblings needing the same DataContext
, Setting DataContext
to their parent is the right answer. I always tend to set DataContext
on the Top-most element possible and if any one or two items need variations bind them out accordingly.
If in MVVM, your VM become the DataContext
almost always of the Top level item of the View. everything else Bind's directly to the element whose property they need pretty much.
上一篇:SearchView.OnCloseListener不会被调用并SearchView、OnCloseListener
下一篇:UserControl:如何添加 MouseWheel 监听器?监听器、UserControl、MouseWheel