RelativeSource работает с вложенным вложенным свойством, а ElementName-нет.


Проблема с нижеприведенным кодом заключается в следующем: привязка к SomeClassProp.SubTextProp не работает (свойство source не устанавливается на содержимое текстового поля), в то время как к 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; }
}

Не упускаю ли я здесь чего-то очевидного?

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

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

1 2

1 ответ:

Ладно, наконец-то я нашел проблему!

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

System.Windows.Data Warning: 108 : BindingExpression (hash=54116930):   At level 0 - for MainWindow.SomeClassProp found accessor RuntimePropertyInfo(SomeClassProp)
System.Windows.Data Warning: 104 : BindingExpression (hash=54116930): Replace item at level 0 with MainWindow (hash=47283970), using accessor RuntimePropertyInfo(SomeClassProp)
System.Windows.Data Warning: 101 : BindingExpression (hash=54116930): GetValue at level 0 from MainWindow (hash=47283970) using RuntimePropertyInfo(SomeClassProp): 
System.Windows.Data Warning: 106 : BindingExpression (hash=54116930):   Item at level 1 is null - no accessor
System.Windows.Data Warning: 80 : BindingExpression (hash=54116930): TransferValue - got raw value {DependencyProperty.UnsetValue}
System.Windows.Data Warning: 88 : BindingExpression (hash=54116930): TransferValue - using fallback/default value ''
System.Windows.Data Warning: 89 : BindingExpression (hash=54116930): TransferValue - using final value ''

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

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

Long story short-moving SomeClassProp intitialization перед тем, как 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 уже был инициализированный).