假设我有一个非常简单的UserControl - 对于所有意图和目的 - 只不过是TextBox:
public partial class FooBox : UserControl
{
public static readonly DependencyProperty FooTextProperty =
DependencyProperty.Register("FooText", typeof(string), typeof(FooBox));
public FooBox()
{
InitializeComponent();
}
public string FooText
{
get { return textBlock.Text; }
set { textBlock.Text = value; }
}
}
<UserControl x:Class="Namespace.FooBox"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Height="300" Width="300">
<Grid>
<TextBlock x:Name="textBlock" />
</Grid>
</UserControl>
在表单上声明为:
<local:FooBox FooText="{Binding Name}" />
表单的DataContext设置为具有Name属性的对象。但这不适合我。我错过了什么?
答案 0 :(得分:19)
DependencyProperty中属性声明的“get”和“set”部分实际上并没有被WPF的数据绑定系统调用 - 它们基本上只是为了满足编译器。
相反,请将您的属性声明更改为:
public string FooText
{
get { return (string)GetValue(FooTextProperty); }
set { SetValue(FooTextProperty, value); }
}
...和您的XAML:
<UserControl ...
x:Name="me">
<Grid>
<TextBlock Text="{Binding FooText,ElementName=me}" />
</Grid>
</UserControl>
现在你的TextBox.Text直接绑定到“FooText”属性,所以你可以将FooText属性绑定到“Name”,就像你现在正在做的那样。
另一种方法是将TextBlock.Text绑定到一个RelativeSource绑定,该绑定在类型为“FooBox”的第一个祖先上找到FooText属性,但我发现这比仅给控件一个内部x更复杂:名称并使用元素绑定。
答案 1 :(得分:6)
原来真正的问题是我期待WPF框架设置我的公共属性,然后我的代码将响应更改并根据新值进行渲染。不是这样。 WPF所做的是直接调用SetValue()并完全绕过公共属性。我必须做的是使用DependencyPropertyDescriptor.AddValueChanged接收属性更改通知并对其做出响应。它看起来像(在ctor里面):
var dpd = DependencyPropertyDescriptor
.FromProperty(MyDependencyProperty, typeof(MyClass));
dpd.AddValueChanged(this, (sender, args) =>
{
// Do my updating.
});