Связывание данных с UserControl в WPF

У меня есть UserControl, который я хочу участвовать в привязке данных. Я настроил свойства зависимостей в пользовательском элементе управления, но не могу заставить его работать.

uc отображает правильный текст, когда я вызываю его со статическим текстом (например, BlueText = "ABC" ). Когда я пытаюсь связать его с локальным публичным свойством, он всегда пуст.

<src:BlueTextBox BlueText="Feeling blue" />            <!--OK-->
<src:BlueTextBox BlueText="{Binding Path=MyString}" /> <!--UserControl always BLANK!-->
<TextBox Text="{Binding Path=MyString}" Width="100"/>  <!--Simple TextBox Binds OK-->

Я откинул код до следующего упрощенного примера. Вот XAML UserControl:

    <UserControl x:Class="Binding2.BlueTextBox" ...
    <Grid>
        <TextBox x:Name="myTextBox" Text="{Binding BlueText}" Foreground="Blue" Width="100" Height="26" />
    </Grid>

Вот код позади UserControl:

public partial class BlueTextBox : UserControl
{
    public BlueTextBox()
    {
        InitializeComponent(); 
        DataContext = this; // shouldn't do this - see solution
    }

    public static readonly DependencyProperty BlueTextProperty =
        DependencyProperty.Register("BlueText", typeof(string), typeof(BlueTextBox));

    public string BlueText
    {
        get { return GetValue(BlueTextProperty).ToString(); }
        set { SetValue( BlueTextProperty, value.ToString() ); }
    }

Кажется, это должно быть очень просто, но я не могу заставить его работать. Спасибо за вашу помощь!

Дополнительная информация: Когда я пытался исправить предложение, предложенное Евгением, я заметил какое-то своеобразное поведение. Я добавил PropertyChangedCallback в метаданные; это позволяет мне наблюдать за установкой BlueText. При установке строки на статическое значение (= "синее" ) происходит событие PropertyChanged. Случай привязки данных не запускает PropertyChanged. Я думаю, это означает, что значение, связанное с данными, не отправляется в UserControl. (Я думаю, что конструктор не вызван в статическом случае)

Решение: Проблемы были правильно идентифицированы Arcturus и jpsstavares. Во-первых, я переписывал привязку данных, когда в конструкторе элемента управления установлен DataContext = this. Это предотвратило получение значения привязки данных. Я также должен был назвать элемент управления x: Name = root и указать Binding ElementName = root int XAML. Чтобы получить привязку TwoWay, мне нужно было установить Mode = TwoWay в вызывающем. Вот правильный код:

<src:BlueTextBox BlueText="{Binding Path=MyString, Mode=TwoWay}}" /> <!--OK-->

Теперь XAML в UserControl:

    <UserControl x:Class="Binding2.BlueTextBox" x:Name="root"...
    <Grid>
        <TextBox x:Name="myTextBox" Text="{Binding ElementName=root, Path=BlueText}" Foreground="Blue" Width="100" Height="26" />
    </Grid>

Наконец, я удалил DataContext = this в конструкторе UserControl.

    public BlueTextBox()
    {
        InitializeComponent(); 
        //DataContext = this; -- don't do this
    }

Спасибо всем за огромную помощь!

Ответ 1

Вы устанавливаете DataContext в самом элементе управления, тем самым перезаписывая DataContext при использовании этого элемента управления в других элементах управления. Взяв ваше обязательство в качестве примера в вашей ситуации:

<src:BlueTextBox BlueText="{Binding Path=MyString}" /> 

После загрузки и установки всего Datacontext он будет искать путь MyString в элементе управления BlueTextBox из-за того, что вы устанавливаете для него DataContext. Я думаю, это не то, как вы намеревались это работать;).

Решение:

Измените привязку текста к одному из двух привязок:

{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type src:BlueTextBox}}, Path=BlueText}

или

Назовите свой элемент управления Root (или что-то в этом роде)

<UserControl x:Name="Root"

{Binding ElementName=Root, Path=BlueText}

И удалите

DataContext = this;

от конструктора вашего UserControl и он должен работать как шарм.

Ответ 2

Я думаю, в этом случае вам нужно установить свойство ElementName в привязке. Что-то вроде этого:

<UserControl x:Class="Binding2.BlueTextBox" x:Name="blueTextBox"...
<Grid>
    <TextBox x:Name="myTextBox" Text="{Binding ElementName=blueTextBox, Path=BlueText}" Foreground="Blue" Width="100" Height="26" />
</Grid>

Ответ 4

Я знаю, что это старая тема, но все же.

Также укажите PropertyChangedCallback в UIPropertyMetadata во время регистрации вашего DP