我有一个wpf用户控件,它公开了一个自定义依赖项属性。在用户控件内,文本块绑定到dp的值。此数据绑定适用于所有方案,除非数据源是对象。
重现这一点所需的最少代码是:
这是用户控件的主要部分
<StackPanel Orientation="Horizontal">
<TextBlock Text="**SimpleUC** UCValue: "/>
<TextBlock Text="{Binding UCValue}"/>
</StackPanel>
和后面的用户控制代码:
public SimpleUC()
{
InitializeComponent();
this.DataContext = this;
}
public string UCValue
{
get { return (string)GetValue(UCValueProperty); }
set { SetValue(UCValueProperty, value); }
}
public static readonly DependencyProperty UCValueProperty =
DependencyProperty.Register("UCValue", typeof(string), typeof(SimpleUC), new UIPropertyMetadata("value not set"));
这是测试窗口。我将项目xml命名空间导入为“custom”
<Window.Resources>
<Style TargetType="{x:Type StackPanel}">
<Setter Property="Margin" Value="20"/>
</Style>
</Window.Resources>
<StackPanel>
<StackPanel>
<TextBlock Text="This fails to bind:"/>
<custom:SimpleUC UCValue="{Binding SomeData}"/>
</StackPanel>
<StackPanel>
<TextBlock>The same binding on a regular control like Label</TextBlock>
<Label Content="{Binding SomeData}"/>
</StackPanel>
<Slider x:Name="sld" />
<StackPanel>
<TextBlock>However, binding the UC to another element value, like a slider works</TextBlock>
<custom:SimpleUC UCValue="{Binding ElementName=sld,Path=Value}"/>
</StackPanel>
</StackPanel>
后面的测试窗口代码是:
public TestWindow()
{
InitializeComponent();
this.DataContext = this;
}
//property to bind to
public string SomeData { get { return "Hello S.O."; } }
当我打开TestWindow上的诊断跟踪时,它会发出错误“BindingExpression path error:
'SomeData' property not found on 'object' ''SimpleUC' (Name='')' ... "
绑定表达式与我在相邻标签中使用的表达式相同,并且工作正常。这种行为对我来说似乎很奇怪。任何人都能解释一下吗?
答案 0 :(得分:8)
您可以将SimpleUC的DataContext设置为自己
public SimpleUC()
{
InitializeComponent();
this.DataContext = this; // wrong way!
}
所以当你在这里使用绑定时
<custom:SimpleUC UCValue="{Binding SomeData}"/>
它在控件的数据上下文中搜索属性SomeData,该上下文设置为此对象,因为SimpleUC构造函数中的代码会覆盖DataContext的值,并且不再按预期将其设置为TestWindow对象。这就是您的解决方案有效的原因 - 它不会影响从窗口继承的DataContext。此外,您可以保留this.DataContext = this;
,但设置元素在哪里显式搜索属性(跳过不相关)
<Window ... Name="wnd1">
<custom:SimpleUC UCValue="{Binding SomeData, ElementName=wnd1}"/>
...
但我的意见是,你的答案中的变体对我来说看起来更方便,将数据上下文设置为这个并不是很好的做法。
希望它有所帮助。
答案 1 :(得分:4)
如果您必须使用UserControl
,那么
<TextBlock
Text="{Binding RelativeSource={RelativeSource Self},
Path=Parent.Parent.UCValue}"
/>
是一种很好的方法,并且
<TextBlock
Text="{Binding UCValue,
RelativeSource={RelativeSource FindAncestor,custom:SimpleUC,1}}"
/>
更好,因为您不依赖于控件层次结构和可能的实例化顺序问题。
但是,我会建议您使用“自定义控件”而不是“用户控件”。他们需要一点点习惯,但它们更强大,因为他们的XAML本身就是模板,这意味着你可以使用TemplateBinding
和{RelativeSource TemplatedParent}
。
无论如何,DataContext = this;
肯定是要避免的。