当开始使用WPF UserControls时,我偶然发现了几种将UserControl的内容绑定到其中一个属性的方法。
以下是我的控件的示例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); }
}
}
以下是我发现将内容绑定到此属性的不同方法:
<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>
这是构造函数:
public MyUserControl()
{
InitializeComponent();
VisualTreeRoot.DataContext = this;
}
我第一次想将UserControl的内容绑定到其中一个属性时,我觉得“嘿,我们只需将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的用户想要将其属性绑定到其他绑定源,则此不起作用。 UserControl需要从其父级继承DataContext才能使其工作。如上所述,通过覆盖它,绑定将不再找到它们的来源。
我的最后一个问题:
答案 0 :(得分:2)
我在绑定到自己的依赖项属性时对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"
x:Name="uc">
<StackPanel>
<TextBox Text="{Binding ElementName=uc,Path=TheText}" />
</StackPanel>
</UserControl>
答案 1 :(得分:2)
DataContext
设置为任何父级的TextBox
都没有TextBox
。因此,你必须告诉DataContext
VisualTree中的哪个是直接控制该属性的控件。StackPanel
设置在TextBox
StackPanel
相应地继承DataContext
。如果UserControl
UserControl
上设置UserControl
本身并不总是错误的(通过构造函数或xaml)。我这样说是因为如果你有20个控件,其中15个需要使用在其当前DataContext
类中定义的属性,5个需要是RelativeSource FindAncestor
的{{1}}的父级,你总是可以对少数群体使用<!-- Can change type to another userControl too and specify Ancestorlevel -->
<TextBlock Text="{Binding TheText, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
绑定。只有我能想到的“方法”可以显示我提到的pt3就像是
TextBlock
^^即使UserControl
的父DataContext
有自己DataContext
至于何时使用什么。
这只是一个合乎逻辑的选择,如果你有多个兄弟姐妹需要相同的DataContext
,将DataContext
设置为他们的父母是正确的答案。我总是倾向于在最顶层的元素上设置DataContext
,如果任何一个或两个项目需要变化,请相应地绑定它们。
如果在MVVM中,您的VM几乎总是成为View的顶级项目的{{1}}。其他一切直接绑定到他们需要的属性的元素。