开始使用 WPF UserControl 时,我偶然发现了几种将 UserControl 的内容绑定(bind)到其属性之一的方法。
这是我的控件的示例 C# 代码:
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); }
}
}
下面是我发现的将内容绑定(bind)到该属性的不同方法:
内容使用与 RelativeSource/AncestorType 的绑定(bind)
<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 的内容绑定(bind)到它的一个属性时,我想“嘿,让我们直接将 UserControl 的 DataContext 设置为其自身吧”:
<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 的用户想要将其属性绑定(bind)到其他绑定(bind)源,这不起作用。 UserControl 需要从其父级继承 DataContext 才能完成这项工作。通过如上所述覆盖它,绑定(bind)将不再找到它们的源。
我最后的问题:
- 所介绍的每种方法的优点和缺点是什么?
- 什么时候应该使用哪种方法?
- 还有更多方法吗?
最佳答案
- 在第一种情况下,
TextBox
没有DataContext
设置为它的任何一个父级。因此,您必须告诉TextBox
在 VisualTree 中的哪个位置是直接带有该属性的控件。 - 第二种情况
DataContext
是在StackPanel
上设置的,TextBox
相应地继承了它。如果您在StackPanel
中有多个控件,这比方法一更好
- 在
UserControl
本身上设置DataContext
并不总是错误的(通过构造函数或 xaml)。我这样说是因为如果你有 20 个控件,其中 15 个需要使用在其当前UserControl
类中定义的属性,5 个需要使用UserControl
的DataContext
,您始终可以对少数使用RelativeSource FindAncestor
绑定(bind)。
只有我能想到的“方法”可以显示我提到的pt3是这样的
<!-- Can change type to another userControl too and specify Ancestorlevel -->
<TextBlock Text="{Binding TheText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
^^ 即使 TextBlock
的父级 UserControl
本身就是 DataContext
至于何时使用什么。
这只是一个合乎逻辑的选择,如果您有多个 sibling 需要相同的 DataContext
,则将 DataContext
设置为他们的 parent 是正确的答案。我总是倾向于将 DataContext
设置在可能的最顶层元素上,如果任何一个或两个项目需要变体,则相应地绑定(bind)它们。
如果在 MVVM 中,您的 VM 几乎总是成为 View 的顶级项目的 DataContext
。其他一切都直接绑定(bind)到他们非常需要其属性的元素。
关于wpf - 将 WPF UserControl 中的内容绑定(bind)到其属性的不同方法的优点/缺点是什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16854031/