Привязка данных к 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 в 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
    }

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


person RaoulRubin    schedule 16.07.2010    source источник


Ответы (4)


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

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

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

Решение:

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

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

or

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

<UserControl x:Name="Root"

{Binding ElementName=Root, Path=BlueText}

И удалите

DataContext = this;

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

person Arcturus    schedule 16.07.2010

Думаю, в этом случае нужно в привязке установить свойство 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>
person jpsstavares    schedule 16.07.2010

Возможно, вам нужно добавить в свое свойство FrameworkPropertyMetadata, где укажите FrameworkPropertyMetadataOptions.AffectsRender и AffectsMeasure.

Статья MSDN о перечислении FrameworkPropertyMetadataOptions

person Eugene Cheverda    schedule 16.07.2010
comment
Пытался установить и AffectsRender, и AffectsMeasure, но это не дало никакого эффекта. Спасибо. - person RaoulRubin; 16.07.2010

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

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

person Jordy van Eijk    schedule 04.07.2011