问题描述
开始使用 WPF UserControl 时,我偶然发现了几种将 UserControl 的内容绑定到其属性之一的方法.
When starting to work with WPF UserControls, I stumbled upon several ways to bind content of a UserControl to one of its properties.
这是我的控件的示例 C# 代码:
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>
可视化树根的DataContext在XAML中设置为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>
可视化树根的DataContext在构造函数中设置为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>
这是构造函数:
public MyUserControl()
{
InitializeComponent();
VisualTreeRoot.DataContext = this;
}
最后但并非最不重要的一点:警告其他在 WPF 中编写 UserControls 的新手
我第一次想将 UserControl 的内容绑定到它的一个属性时,我虽然嘿,让我们直接将 UserControl 的 DataContext 设置为它自己":
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}}">
或者:
public MyUserControl()
{
InitializeComponent();
this.DataContext = this;
}
但是,如果 UserControl 的用户想要将其属性绑定到其他绑定源,则这不起作用.UserControl 需要从其父级继承 DataContext 才能完成这项工作.通过如上所述覆盖它,绑定将不再找到它们的来源.
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.
我最后的问题:
- 所介绍的每种方法的优缺点是什么?
- 什么时候应该使用哪种方法?
- 还有更多方法吗?
推荐答案
- 好吧,在第一种情况下,
TextBox
没有设置为它的任何父项的DataContext
.因此,您必须告诉TextBox
在 VisualTree 中的哪个位置是直接在其上具有该属性的控件. - 第二种情况
DataContext
设置在StackPanel
上,TextBox
相应地继承了它.如果StackPanel
中有多个控件,这比方法一更好 - 在
UserControl
本身上设置DataContext
并不总是错误的(通过构造函数或 xaml).我这样说是因为如果您有 20 个控件,其中 15 个需要使用在其当前UserControl
类中定义的属性,而 5 个需要使用UserControl
的父级code>DataContext,您始终可以对少数使用RelativeSource FindAncestor
绑定. - 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.
我能想到的只有方法"可以显示我提到的 pt3 类似于
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}}}" />
^^ 即使 TextBlock
的父 UserControl
将自身作为 DataContext
^^ This will work fine even if the TextBlock
's parent UserControl
has itself as it's DataContext
至于何时使用什么.
这只是一个合乎逻辑的选择,如果您有多个兄弟姐妹需要相同的 DataContext
,那么将 DataContext
设置为他们的父级是正确的答案.我总是倾向于在可能的最顶层元素上设置 DataContext
,如果任何一两个项目需要变体,则相应地将它们绑定.
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.
如果在 MVVM 中,您的 VM 几乎总是成为视图的顶级项的 DataContext
.其他一切都直接绑定到他们非常需要其属性的元素.
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 中的内容绑定到其属性的不同方式的优缺点是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!