将 WPF UserControl 中的内容绑定到其属性的不同方式的优点/缺点是什么? [英] What are the advantages/disadvantages of the different ways of binding content in a WPF UserControl to its properties?
问题描述
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:
Content uses binding with RelativeSource/AncestorType
<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>
DataContext of visual tree root is set to UserControl in XAML
<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>
DataContext of visual tree root is set to UserControl in constructor
<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;
}
Last but not least: A warning for other people new to programming UserControls in WPF
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 theTextBox
set to any of it's Parent's. Hence you're having to tell theTextBox
where in the VisualTree is the control with that property directly on it. - Second case
DataContext
is set onStackPanel
which theTextBox
inherit's accordingly. This is better than approach one if you have multiple control's in theStackPanel
- Setting
DataContext
on theUserControl
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 currentUserControl
class and 5 that need's the parent of theUserControl
'sDataContext
, You can always use aRelativeSource 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.
这篇关于将 WPF UserControl 中的内容绑定到其属性的不同方式的优点/缺点是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!