Моя программа содержит несколько экземпляров этой строки:
<local:MyClass Data="{Binding}"/>
т.е. свойство Data
привязано к контексту данных окружающего окна. Когда значение окна DataContext
изменяется, привязка иногда обновляется, иногда нет; это зависит от положения <local:MyClass...>
в файле XAML.
Вот пример ( РЕДАКТИРОВАТЬ: Я изменил {Binding}
на {Binding Path=DataContext, ElementName=myWindow}
, чтобы подчеркнуть, что проблема не связана с наследованием DataContext
):
XAML код:
<Window x:Class="BindTest.MainWindow"
x:Name="myWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:BindTest"
Title="Binding Test" Height="101" Width="328">
<Window.Tag>
<local:MyClass x:Name="bindfails" Data="{Binding Path=DataContext, ElementName=myWindow}"/>
</Window.Tag>
<StackPanel Orientation="Horizontal">
<Button Margin="5" Padding="5" Click="SetButtonClicked">Set DataContext</Button>
<Button Margin="5" Padding="5" Click="ReadButtonClicked">Read Bound Property</Button>
<local:MyClass x:Name="bindworks" Data="{Binding Path=DataContext, ElementName=myWindow}"/>
</StackPanel>
</Window>
C # код:
using System.Windows;
namespace BindTest
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private void SetButtonClicked(object sender, RoutedEventArgs e)
{
DataContext = 1234;
}
private void ReadButtonClicked(object sender, RoutedEventArgs e)
{
string txtA = (bindfails.Data == null ? "null" : bindfails.Data.ToString());
string txtB = (bindworks.Data == null ? "null" : bindworks.Data.ToString());
MessageBox.Show(string.Format("bindfails.Data={0}\r\nbindworks.Data={1}", txtA, txtB));
}
}
public class MyClass : FrameworkElement
{
#region Dependency Property "Data"
public object Data
{
get { return (object)GetValue(DataProperty); }
set { SetValue(DataProperty, value); }
}
public static readonly DependencyProperty DataProperty =
DependencyProperty.Register("Data", typeof(object), typeof(MyClass), new UIPropertyMetadata(null));
#endregion
}
}
Сначала нажмите кнопку «Установить DataContext», чтобы изменить контекст данных. Затем нажмите кнопку «Read Bound Property», чтобы отобразить это сообщение:
bindfails.Data = нуль
bindworks.Data = 1234
Очевидно, что привязка данных была обновлена только для элемента MyClass
, который является дочерним для StackPanel
; но привязка данных не была обновлена для элемента MyClass
, на который ссылается Window.Tag
.
EDIT2: Я также обнаружил, что привязка работает при программном добавлении привязки внутри конструктора MainWindow
:
Binding binding = new Binding("DataContext") {Source = this};
bindfails.SetBinding(MyClass.DataProperty, binding);
Привязка не выполняется, только если она объявлена в XAML. Кроме того, проблема не относится к DataContext
; это также происходит, когда я использую другие свойства Window
, такие как Title
.
Может кто-нибудь объяснить это поведение и предложить, как разрешить использование {Binding}
в XAML в обоих случаях?
EDIT3: Приведенный выше код не полностью эквивалентен расширению разметки {Binding}. 100% эквивалентный код:
Binding binding = new Binding("DataContext") {ElementName = "myWindow"};
bindfails.SetBinding(MyClass.DataProperty, binding);
Когда я использую этот код, привязка также завершается неудачно (как при связывании в XAML), и в отладочный вывод записывается следующее диагностическое сообщение:
System.Windows.Data Ошибка: 4: не удается найти источник для привязки со ссылкой «ElementName = myWindow».
Очевидно, что свойство ElementName
ищет только визуальное дерево или логическое дерево, даже если это не задокументировано в онлайн-документации WPF. Возможно, в XAML нет простого способа установить такую привязку.