Я создаю приложение WPF с пользовательскими элементами управления UserControls и пытаюсь понять, как должны работать привязки свойств. Я не могу получить даже самую базовую c привязку к работе, и ее достаточно просто превратить в крошечный пример, поэтому я подумал, что кто-то с большим опытом работы с WPF сможет поставить меня на правильный путь.
Я определил пользовательский UserControl с именем TestControl , который предоставляет свойство Foo , которое предназначено для установки в XAML при каждом размещении UserControl.
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 я просто помещаю один экземпляр 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>
Я ожидаю, что при сборке и запуске этого приложения я увижу окно с одной кнопкой с надписью «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
, et c., А также установить UpdateSourceTrigger=PropertyChanged
и проверять обновления с помощью NotifyOnTargetUpdated=True
... кажется, ничего не приводит к обновлению текста в пользовательском интерфейсе для соответствия базовое значение свойства, хотя значение свойства, похоже, обновляется очень хорошо.
Что я делаю не так? Я чувствую, что есть просто простое и фундаментальное недоразумение в том, как я к этому подхожу.
edit:
Возни немного больше и читая похожие вопросы привел меня к потенциальному исправлению: добавление имени к элементу root UserControl в TestControl.xaml (x:Name="control"
) и изменение привязки для явного указания этого элемента управления ({Binding Foo, ElementName=control}
).
Я предполагаю, что по умолчанию {Binding Foo}
в элементе Button просто означает "найти свойство с именем 'Foo' в этом элементе управления Button" , тогда как я предполагал, что это будет означать "найти свойство с именем 'Foo' в контексте, в котором эта кнопка объявляется, т.е. в TestControl" .
Является ли указание явного ElementName лучшим решением здесь?