WPF привязка данных с пользовательским управлением - PullRequest
8 голосов
/ 12 февраля 2010

У меня есть пользовательский элемент управления wpf, который предоставляет одно пользовательское свойство зависимости. Внутри пользовательского элемента управления текстовый блок привязывается к значению dp. Эта привязка данных работает во всех сценариях, кроме случаев, когда источником данных является объект.

Минимальный код, необходимый для воспроизведения:

это основная часть пользовательского элемента управления

<StackPanel Orientation="Horizontal">
    <TextBlock Text="**SimpleUC** UCValue: "/>
    <TextBlock Text="{Binding UCValue}"/>
</StackPanel>

и код управления пользователем позади:

    public SimpleUC()
    {
        InitializeComponent();
        this.DataContext = this;
    }

    public string UCValue
    {
        get { return (string)GetValue(UCValueProperty); }
        set { SetValue(UCValueProperty, value); }
    }

    public static readonly DependencyProperty UCValueProperty =
        DependencyProperty.Register("UCValue", typeof(string), typeof(SimpleUC), new UIPropertyMetadata("value not set"));

это тестовое окно. Я импортировал свое пространство имен xml проекта как "custom"

<Window.Resources>
    <Style TargetType="{x:Type StackPanel}">
        <Setter Property="Margin" Value="20"/>
    </Style>
</Window.Resources>
<StackPanel>
    <StackPanel>
        <TextBlock Text="This fails to bind:"/>
        <custom:SimpleUC UCValue="{Binding SomeData}"/> 
    </StackPanel>
    <StackPanel>
        <TextBlock>The same binding on a regular control like Label</TextBlock>
        <Label Content="{Binding SomeData}"/>
    </StackPanel>
    <Slider x:Name="sld" />
    <StackPanel>
        <TextBlock>However, binding the UC to another element value, like a slider works</TextBlock>
        <custom:SimpleUC UCValue="{Binding ElementName=sld,Path=Value}"/>
    </StackPanel>
</StackPanel>

и код окна теста:

public TestWindow()
{
    InitializeComponent();
    this.DataContext = this;
}

//property to bind to
public string SomeData { get { return "Hello S.O."; } } 

Когда я включаю диагностическую трассировку в TestWindow, он выдает ошибку «Ошибка пути BindingExpression: 'SomeData' property not found on 'object' ''SimpleUC' (Name='')' ... "
Выражение привязки такое же, как и в соседней метке, и оно работало нормально. Такое поведение кажется мне очень странным. Кто-нибудь может пролить свет?

Ответы [ 2 ]

8 голосов
/ 13 февраля 2010

Вы устанавливаете DataContext вашего SimpleUC себе здесь

public SimpleUC()
{
    InitializeComponent();
    this.DataContext = this; // wrong way!
}

, поэтому при использовании привязки здесь

<custom:SimpleUC UCValue="{Binding SomeData}"/>

он ищет свойство SomeData в контексте данных элемента управления, которое установлено для этого объектапотому что код в конструкторе SimpleUC переопределяет значение DataContext и больше не устанавливается в объект TestWindow, как вы ожидали.Вот почему ваше решение работает - оно не влияет на DataContext, который наследуется от окна.Также вы можете оставить this.DataContext = this;, но установить элемент, где явно искать свойство, как это (пропущено неактуально)

<Window ... Name="wnd1">
    <custom:SimpleUC UCValue="{Binding SomeData, ElementName=wnd1}"/>
...

Но я считаю, что ваш вариант ответа выглядит более удобным для меня, устанавливая контекст данных для это не очень хорошая практика.

Надеюсь, это поможет.

4 голосов
/ 13 февраля 2010

Если вы должны использовать UserControl, ваш

<TextBlock
  Text="{Binding RelativeSource={RelativeSource Self},
                 Path=Parent.Parent.UCValue}"
/>

это хороший способ сделать это и

<TextBlock
  Text="{Binding UCValue,
                 RelativeSource={RelativeSource FindAncestor,custom:SimpleUC,1}}"
/>

лучше, потому что вы не полагаетесь на иерархию элементов управления и возможные проблемы порядка создания экземпляров.

Однако я бы рекомендовал для такого рода ситуаций использовать «пользовательские элементы управления» вместо «пользовательских элементов управления». Им нужно немного привыкнуть, но они намного мощнее, потому что их XAML - это сам шаблон, который означает, что вы можете использовать TemplateBinding и {RelativeSource TemplatedParent}.

В любом случае, DataContext = this; определенно следует избегать.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...