事情是我总是想绑定控件对DataContext属性。因为我不喜欢在绑定表达式中指定源。但是,我不想显式地绑定控件的DataContext属性,而是使用另一个指定的和自描述的属性,如Items或Plugins或任何控件的目的。现在,我需要一种方法来设置DataContext属性,每当该自描述属性真正确定控件的上下文设置时。此外,我希望DataContext始终与此属性相同。如何做到这一点?
我尝试用回调指定PropertyMetadata,该回调将在新接收的值上设置DataContext。这行不通。首先,因为这个回调不是为属性的默认值调用的。其次,也是最有趣的一点,我观察到一些非常奇怪的行为。让我用callstack来解释一下:
这是我的PropertyMetadata在回调断点:
new PropertyMetadata((d, e) => ((SearchSettings)d).DataContext = e.NewValue)
这是调用栈(行尾有注释):
3. Bla-bla-bla.SearchSettings..cctor.AnonymousMethod__7(DependencyObject d, DependencyPropertyChangedEventArgs e) /* Setting property back to null. Why??? */
2. [External Code]
1. Bla-bla-bla.SearchSettings..cctor.AnonymousMethod__7(DependencyObject d, DependencyPropertyChangedEventArgs e) /* This is where the breakpoint hit first. Settings a new value to a property as a result of databinding. */
那么,我怎么做呢?或者我应该做这件事吗?顺便说一句,我是WPF的新手,所以我可能会错的。
根据您最近一个问题的答案,DataContext是绑定将用作其数据源的对象。
当我建议将DataContext设置为页面或控件时(下面,在原始答案中),这样您就不必像原始问题中所述的那样在Binding中指定Source
属性。
示例 -而不是像
那样指定绑定: {Binding Path=PropertyName, RelativeSource={RelativeSource AncestorType={x:Type ns:ControlName}}}
你可以直接用
{Binding Path=PropertyName}
作为容器DataContext
属性被设置为ControlName
的实例(这仅适用于指定DataContext = this
, 而不是 DataContext = this.DataContext
,因为这将只是将其设置为自身并且毫无意义)。
现在对于Page
或Window
对象,PropertyName
可以是寄存器DependencyProperty
实例,也可以是股票标准Property
,引发INotifyPropertyChanged.PropertyChanged
事件,通知XAML中的子节点属性已经更改,并根据需要更新自己。
对于Control
对象,您仍然可以使用任何一种方法-但是,如果您希望能够绑定到这些属性,则需要将它们定义为DependencyProperty
s。
你能更新你的文章与任何来源为我们看你吗?
原始答:
我不完全确定我理解了您的最终目标,但是为您的控件指定DataContext的最懒惰的方法是在构造函数中将页面的DataContext属性设置为它自己。
this.DataContext = this;
这消除了在绑定中设置Source和RelativeSource属性的需要,同时仍然允许您直接绑定到页面属性。
的例子:
public class MyControl : UserControl
{
public static readonly DependencyProperty SomeStringProperty = DependencyProperty.Register("SomeString", typeof(string), typeof(ownerclass), new UIPropertyMetadata(0));
public string SomeString
{
get { return (string)GetValue(SomeStringProperty); }
set { SetValue(SomeStringProperty, value); }
}
public MyControl()
{
InitializeComponent();
DataContext = this;
}
}
然后在XAML中:
<TextBlock Text="{Binding Path=SomeString}" />
我真的不明白为什么要创建一个属性来代替DataContext
DataContext
的目的是引用控件背后的实际数据。为什么要为一个已经存在的属性创建第二个属性呢?对我来说,这就像说你想重写控件的IsReadOnly
属性,所以它读DisableEditing
-没有目的。
此外,为什么要将其绑定到应用层?WPF的全部意义在于将业务/应用程序逻辑从UI中分离出来,而您要做的就是将两者结合在一起。如果你想要这种行为,请使用WinForms。
如果您想确保您的UserControl
仅与User
DataContext一起使用,请使用DataTemplate
。
<DataTemplate DataType="{x:Type local:User}">
<local:MyUserControl /> <!-- DataContext will be User -->
</DataTemplate>
<!-- This will display a User object, but because of the DataTemplate it will
draw it using your UserControl instead of the default User.ToString() -->
<ContentControl Content="{Binding CurrentUser}" />
如果你真的想确保你的UserControl
只接收User
对象作为DataContext
,在初始化this.DataContext
是User
对象时做一些验证检查。不要创建某种自定义属性,人们需要记住在他们想要使用你的控件时绑定它。