WPF: Binding не может найти источник - PullRequest
2 голосов
/ 30 ноября 2011

Я пытаюсь создать свой собственный ContentControl, производный от Control, для полного понимания концепций дерева темных wpf. На данный момент я только что реализовал логическую часть (Content) ContentControl.

Мой код позади:

[ContentProperty("Content")]
public class MyContentControl : Control
{
    public MyContentControl()
    {

    }

    public Object Content
    {
        get { return (Object)GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

    public static readonly DependencyProperty ContentProperty =
        DependencyProperty.Register("Content", typeof(Object), typeof(MyContentControl), new UIPropertyMetadata());

}

XAML:

<StackPanel x:Name="stackPanel">
    <TextBlock Visibility="Collapsed" x:Name="textBlock" Text="Hello World"/>
    <ContentControl>
        <TextBlock Background="LightBlue" Text="{Binding Text, ElementName=textBlock}"/>
    </ContentControl>
    <local:MyContentControl>
        <TextBlock Text="{Binding Text, ElementName=textBlock}"/>
    </local:MyContentControl>
</StackPanel>

Я получил следующую ошибку привязки:

System.Windows.Data Ошибка: 4: не удается найти источник для привязки со ссылкой «ElementName = textBlock». BindingExpression: Path = Text; DataItem = NULL; целевым элементом является TextBlock (Name = ''); Целевым свойством является «Текст» (тип «Строка»)

Это похоже на то, что внутренний текстовый блок не может подняться в логическом дереве и найти оригинальный текстовый блок, с которым он должен связываться. Мне не удалось установить myContentControl в качестве родителя объекта Content.

Есть идеи?

Спасибо за ваше время.

Jonas

Ответы [ 2 ]

4 голосов
/ 30 ноября 2011

Соответствующий вопрос: Привязка ElementName. Использует ли он визуальное дерево или логическое дерево

Связывание, которое вы хотите, невозможно, потому что тот же экземпляр MyContentControl теоретически может быть использован где-то еще в приложении, где элемент "textBlock" не находится в области действия.

Если вы хотите выполнить привязку такого типа, вы можете использовать вместо этого Ресурс:

xmlns:clr="clr-namespace:System;assembly=mscorlib"

<StackPanel>
    <StackPanel.Resources>
        <clr:String x:Key="MyText">Hanky Panky</clr:String>
    </StackPanel.Resources>
    <TextBlock Text="{StaticResource MyText}" />

    <ContentControl>
        <TextBlock Text="{Binding Source={StaticResource MyText}}" />
    </ContentControl>
</StackPanel>
2 голосов
/ 01 декабря 2011

Мне просто нужно было применить FrameworkElement.AddLogicalChild и FrameworkElement.RemoveLogicalChild, когда ContentChanged и привязка правильно применяются (проверено с инспектором WPF).

Так что все это о LogicalTree (и, возможно, именная область xamlнаследуется от логического родителя).TextBlock внутри MyContentControl получает MyContentControl как родительский при вызове MyContentControl.AddLogicalChild (TextBlock).

Мой код:

[ContentProperty("Content")]
public class MyContentControl : Control
{
    public MyContentControl()
    {
        Content = new UIElementCollection(this, this);
    }


    public Object Content
    {
        get { return (Object)GetValue(ContentProperty); }
        set { SetValue(ContentProperty, value); }
    }

    public static readonly DependencyProperty ContentProperty =
        DependencyProperty.Register("Content", typeof(Object), typeof(MyContentControl), new UIPropertyMetadata(new PropertyChangedCallback(OnContentChanged)));

    public static void OnContentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        MyContentControl c = (MyContentControl)d;

        if (e.OldValue != null)
        {
            c.RemoveLogicalChild(e.OldValue);
        }

        c.AddLogicalChild(e.NewValue);
    }

    protected override System.Collections.IEnumerator LogicalChildren
    {
        get
        {
            List<Object> l = new List<object>();
            if (Content != null)
                l.Add(Content);

            return l.GetEnumerator();
        }
    }
}
...