RelativeSource работает с (вложенным) подсвойством, в то время как ElementName не

Проблема с кодом ниже: привязка к SomeClassProp.SubTextProp не работает (свойство источника не устанавливается для содержимого текстового поля), а для TextProp оно делает.

XAML:

<Window x:Class="TestWPF.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow"
        Name="wMain"
        SizeToContent="WidthAndHeight">
    <StackPanel>
        <TextBox Text="{Binding ElementName=wMain, Path=SomeClassProp.SubTextProp}" Width="120" Height="23" />
        <TextBox Text="{Binding ElementName=wMain, Path=TextProp}" Width="120" Height="23" />
    </StackPanel>
</Window>

и код:

public partial class MainWindow : Window
{
    public SomeClass SomeClassProp { get; set; }
    public string TextProp { get; set; }

    public MainWindow()
    {
        InitializeComponent();
        SomeClassProp = new SomeClass();
    }
}

public class SomeClass
{
    public string SubTextProp { get; set; }
}

Я что-то упускаю здесь очевидное?

Обратите внимание, что эта привязка необходима для работы от цели (текстовое поле) к источнику (свойство класса).

ОБНОВЛЕНИЕ: Когда я меняю привязку с ElementName=wMain в RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}} - Обе привязки работают. Так что проблема специфична для ElementName обязательное свойство.

1 ответ

Решение

Хорошо, наконец, я нашел проблему!

После добавления diag:PresentationTraceSources.TraceLevel=High для привязки defs (кстати, очень полезная вещь, при отсутствии обычной пошаговой отладки) в выводе я увидел следующее:

Предупреждение System.Windows.Data: 108: BindingExpression (hash=54116930): на уровне 0 - для MainWindow.SomeClassProp найден метод доступа RuntimePropertyInfo(SomeClassProp)
Предупреждение System.Windows.Data: 104: BindingExpression (hash=54116930): заменить элемент на уровне 0 на MainWindow (hash=47283970), используя метод доступа RuntimePropertyInfo(SomeClassProp)
Предупреждение System.Windows.Data: 101: BindingExpression (hash=54116930): GetValue на уровне 0 из MainWindow (hash = 47283970) с использованием RuntimePropertyInfo(SomeClassProp): 
Предупреждение System.Windows.Data: 106: BindingExpression (hash=54116930): элемент на уровне 1 пуст - нет доступа
Предупреждение System.Windows.Data: 80: BindingExpression (hash=54116930): TransferValue - получено необработанное значение {DependencyProperty.UnsetValue}
Предупреждение System.Windows.Data: 88: BindingExpression (hash=54116930): TransferValue - использование запасного значения / значения по умолчанию ''
Предупреждение System.Windows.Data: 89: BindingExpression (hash=54116930): TransferValue - использование окончательного значения ''

Проблема была в порядке инициализации MainWindow!

Итак, в момент, когда привязка была построена, мое свойство уровня 0 (SomeClassProp) еще не был инициализирован, что привело к полному сбою привязки (по какой-то причине без выдачи предупреждения о бинге обычного уровня).

Короче говоря - трогательно SomeClassProp инициализация перед InitializeComponent() в MainWindow конструктор сделал свое дело, привязка начала работать с ElementName тоже:

public MainWindow()
{
    SomeClassProp = new SomeClass();
    InitializeComponent();
}

Ответ на вопрос - почему это работает с помощью RelativeSource свойство - лежит в этих строках выходного журнала:

System.Windows.Data Warning: 66 : BindingExpression (hash=28713467): RelativeSource (FindAncestor) requires tree context
System.Windows.Data Warning: 65 : BindingExpression (hash=28713467): Resolve source deferred

Инициализация контекста данных с помощью RelativeSource требует древовидного контекста и откладывается до некоторого момента времени после построения Window (к тому времени SomeClassProperty был уже инициализирован).

Другие вопросы по тегам