如何通过绑定在 WPF UserControl 中引用自定义 属性 值?
How do I reference a custom property value in a WPF UserControl via Binding?
我正在构建一个带有自定义用户控件的 WPF 应用程序,我正在尝试了解 属性 绑定应该如何工作。我连最基本的绑定都无法工作,而且它很简单,可以提炼成一个小例子,所以我想有更多 WPF 经验的人可能会让我走上正轨。
我定义了一个名为 TestControl 的自定义 UserControl,它公开了一个 Foo 属性,旨在每当放置 UserControl 时在 XAML 中设置。
TestControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace BindingTest
{
public partial class TestControl : UserControl
{
public static readonly DependencyProperty FooProperty = DependencyProperty.Register("Foo", typeof(string), typeof(TestControl));
public string Foo
{
get { return (string)GetValue(FooProperty); }
set { SetValue(FooProperty, value); }
}
public TestControl()
{
InitializeComponent();
}
}
}
TestControl 的标记只是将其定义为具有单个按钮的控件,其标签文本显示 Foo 的当前值 属性:
TestControl.xaml
<UserControl x:Class="BindingTest.TestControl"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BindingTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Button Content="{Binding Foo}" />
</Grid>
</UserControl>
在我的 MainWindow class 中,我只放置了一个 TestControl 实例,其 Foo 属性 设置为 "Hello"。
MainWindow.xaml
<Window x:Class="BindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BindingTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:TestControl Foo="Hello" />
</Grid>
</Window>
我希望在构建和启动此应用程序时,我会看到 window 和一个显示为 "Hello" 的按钮。但是,按钮是空白的:绑定似乎不起作用。
如果我向 TestControl 的按钮添加点击处理程序,我可以验证该值是否正在幕后更新:
// Added to TestControl.xaml.cs:
private void Button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("Button clicked; Foo is '{0}'", Foo);
}
// Updated in TestControl.xaml:
// <Button Content="{Binding Foo}" Click="Button_Click" />
当我点击按钮时,我得到 Button clicked; Foo is 'Hello'
,但是 GUI 永远不会更新。我试过使用 Path=Foo
、XPath=Foo
等,以及设置 UpdateSourceTrigger=PropertyChanged
并使用 NotifyOnTargetUpdated=True
验证更新... UI 正在更新以匹配基础 属性 值,即使 属性 值似乎正在更新得很好。
我做错了什么?我觉得我处理这个问题的方式存在一个简单而根本的误解。
编辑:
仔细研究和阅读 使我找到了一个潜在的解决方法:即,向 TestControl.xaml (x:Name="control"
) 中的根 UserControl 元素添加一个名称,以及更改绑定以显式指定该控件 ({Binding Foo, ElementName=control}
)。
我猜默认情况下,Button 元素上的 {Binding Foo}
仅表示 "find a property named 'Foo' on this Button control",而我假设它表示 "find a property named 'Foo' in the context that this Button is being declared in, i.e. on the TestControl".
指定一个明确的 ElementName 是最好的解决方法吗?
您必须将绑定的源对象设置为 UserControl 实例,例如像这样:
<Button Content="{Binding Foo, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
或
<UserControl ... x:Name="theControl">
...
<Button Content="{Binding Foo, ElementName=theControl}"/>
如果您有很多这样的绑定,您还可以将 UserControl 的 XAML 中顶级元素的 DataContext 设置为 UserControl 实例:
<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
<Button Content="{Binding Foo}" />
<Button Content="{Binding Bar}" />
</Grid>
但是,您必须避免设置 UserControl 的 DataContext("expert" 博主经常推荐),因为这会破坏 UserControl 属性的基于 DataContext 的绑定,例如
<local:TestControl Foo="{Binding SomeFoo}" />
我正在构建一个带有自定义用户控件的 WPF 应用程序,我正在尝试了解 属性 绑定应该如何工作。我连最基本的绑定都无法工作,而且它很简单,可以提炼成一个小例子,所以我想有更多 WPF 经验的人可能会让我走上正轨。
我定义了一个名为 TestControl 的自定义 UserControl,它公开了一个 Foo 属性,旨在每当放置 UserControl 时在 XAML 中设置。
TestControl.xaml.cs
using System.Windows;
using System.Windows.Controls;
namespace BindingTest
{
public partial class TestControl : UserControl
{
public static readonly DependencyProperty FooProperty = DependencyProperty.Register("Foo", typeof(string), typeof(TestControl));
public string Foo
{
get { return (string)GetValue(FooProperty); }
set { SetValue(FooProperty, value); }
}
public TestControl()
{
InitializeComponent();
}
}
}
TestControl 的标记只是将其定义为具有单个按钮的控件,其标签文本显示 Foo 的当前值 属性:
TestControl.xaml
<UserControl x:Class="BindingTest.TestControl"
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"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:BindingTest"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid>
<Button Content="{Binding Foo}" />
</Grid>
</UserControl>
在我的 MainWindow class 中,我只放置了一个 TestControl 实例,其 Foo 属性 设置为 "Hello"。
MainWindow.xaml
<Window x:Class="BindingTest.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:BindingTest"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<local:TestControl Foo="Hello" />
</Grid>
</Window>
我希望在构建和启动此应用程序时,我会看到 window 和一个显示为 "Hello" 的按钮。但是,按钮是空白的:绑定似乎不起作用。
如果我向 TestControl 的按钮添加点击处理程序,我可以验证该值是否正在幕后更新:
// Added to TestControl.xaml.cs:
private void Button_Click(object sender, RoutedEventArgs e)
{
Console.WriteLine("Button clicked; Foo is '{0}'", Foo);
}
// Updated in TestControl.xaml:
// <Button Content="{Binding Foo}" Click="Button_Click" />
当我点击按钮时,我得到 Button clicked; Foo is 'Hello'
,但是 GUI 永远不会更新。我试过使用 Path=Foo
、XPath=Foo
等,以及设置 UpdateSourceTrigger=PropertyChanged
并使用 NotifyOnTargetUpdated=True
验证更新... UI 正在更新以匹配基础 属性 值,即使 属性 值似乎正在更新得很好。
我做错了什么?我觉得我处理这个问题的方式存在一个简单而根本的误解。
编辑:
仔细研究和阅读 x:Name="control"
) 中的根 UserControl 元素添加一个名称,以及更改绑定以显式指定该控件 ({Binding Foo, ElementName=control}
)。
我猜默认情况下,Button 元素上的 {Binding Foo}
仅表示 "find a property named 'Foo' on this Button control",而我假设它表示 "find a property named 'Foo' in the context that this Button is being declared in, i.e. on the TestControl".
指定一个明确的 ElementName 是最好的解决方法吗?
您必须将绑定的源对象设置为 UserControl 实例,例如像这样:
<Button Content="{Binding Foo, RelativeSource={RelativeSource AncestorType=UserControl}}"/>
或
<UserControl ... x:Name="theControl">
...
<Button Content="{Binding Foo, ElementName=theControl}"/>
如果您有很多这样的绑定,您还可以将 UserControl 的 XAML 中顶级元素的 DataContext 设置为 UserControl 实例:
<Grid DataContext="{Binding RelativeSource={RelativeSource AncestorType=UserControl}}">
<Button Content="{Binding Foo}" />
<Button Content="{Binding Bar}" />
</Grid>
但是,您必须避免设置 UserControl 的 DataContext("expert" 博主经常推荐),因为这会破坏 UserControl 属性的基于 DataContext 的绑定,例如
<local:TestControl Foo="{Binding SomeFoo}" />