Связывание DataContext с другим свойством в WPF

Дело в том, что я всегда хочу привязать элементы управления к свойству DataContext. Потому что мне не нравится указывать Source в выражении Binding. Однако я не хочу явно связывать свойство DataContext своих элементов управления, а использую другие назначенные и описательные свойства, такие как Items или Plugins, или какова бы ни была цель элемента управления. Теперь мне нужен способ установить свойство DataContext всякий раз, когда устанавливается это самоописательное свойство, действительно определяющее контекст элемента управления. Более того, я хочу, чтобы DataContext всегда был таким же, как это свойство. Как это можно сделать?

Я попытался указать PropertyMetadata с обратным вызовом, который установил бы DataContext на вновь полученное значение. Не работает Во-первых, потому что этот обратный вызов не вызывается для значения свойства по умолчанию. А во-вторых, и это самое интересное, я заметил очень странное поведение. Позвольте мне объяснить это с помощью callstack:

Это мои PropertyMetadata с точкой останова в обратном вызове:

new PropertyMetadata((d, e) => ((SearchSettings)d).DataContext = e.NewValue)

И это callstack (есть комментарии на концах строк):

3. Bla-bla-bla.SearchSettings..cctor.AnonymousMethod__7(DependencyObject d, DependencyPropertyChangedEventArgs e) /* Setting property back to null. Why??? */
2. [External Code]  
1. Bla-bla-bla.SearchSettings..cctor.AnonymousMethod__7(DependencyObject d, DependencyPropertyChangedEventArgs e) /* This is where the breakpoint hit first. Settings a new value to a property as a result of databinding. */

Итак, как мне это сделать? Или я должен хотеть сделать это вообще? Кстати, я новичок в WPF, так что я могу все неправильно понять.

2 ответа

Я действительно не вижу причин для создания свойства, которое заменяет DataContext

Цель DataContext это ссылаться на фактические данные за вашим контролем. Зачем вам создавать второе свойство для того, которое уже существует? Для меня это все равно, что сказать, что ты хочешь переписать IsReadOnly свойство элемента управления, поэтому он читает DisableEditing - нет никакой цели для этого.

И, кроме того, почему вы хотите привязать его к своему прикладному уровню? Весь смысл WPF состоит в том, чтобы отделить бизнес-логику приложения от пользовательского интерфейса, а вы пытаетесь связать их вместе. Используйте WinForms, если вы хотите такое поведение.

Если вы хотите быть уверены, что ваш UserControl используется только с User DataContext, используйте DataTemplate,

<DataTemplate DataType="{x:Type local:User}">
    <local:MyUserControl /> <!-- DataContext will be User -->
</DataTemplate>

<!-- This will display a User object, but because of the DataTemplate it will 
     draw it using your UserControl instead of the default User.ToString() -->
<ContentControl Content="{Binding CurrentUser}" /> 

Если вы действительно хотите, чтобы ваш UserControl только получает User объект как DataContext, сделайте некоторую проверку проверки на инициализацию, которая this.DataContext это User объект. Не создавайте какое-либо пользовательское свойство, которое люди должны помнить, чтобы связывать каждый раз, когда они хотят использовать ваш контроль.

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

Когда я предложил установить DataContext для страницы или элемента управления (ниже, в исходном ответе), это было так, что вам не нужно было указывать Source собственность в вашем Binding, как указано в вашем первоначальном вопросе.

Пример. Вместо того, чтобы указывать привязку, например:

{Binding Path=PropertyName, RelativeSource={RelativeSource AncestorType={x:Type ns:ControlName}}}

ты мог бы просто использовать

{Binding Path=PropertyName}

как контейнеры DataContext свойство было установлено на экземпляр ControlName (это только в случае, если вы укажете DataContext = thisне DataContext = this.DataContext так как это будет просто установить его для себя и будет бессмысленно).

Теперь для Page или же Window объекты, PropertyName может быть либо быть регистром DependencyProperty экземпляр, или это может быть стандарт акций Property что подняло INotifyPropertyChanged.PropertyChanged событие, чтобы уведомить детей в XAML, что свойство изменилось, и они обновляют себя по мере необходимости.

За Control объекты, вы все равно можете использовать любой метод - однако, если вы хотите иметь возможность привязки к этим свойствам, они должны быть определены как DependencyPropertys.

Можете ли вы обновить свой пост любым источником, чтобы мы могли его найти?


Оригинальный ответ:

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

this.DataContext = this;

Это устраняет необходимость устанавливать свойства Source и RelativeSource в вашей привязке, в то же время позволяя вам привязывать непосредственно к свойствам страницы.

Пример:

public class MyControl : UserControl
{
    public static readonly DependencyProperty SomeStringProperty = DependencyProperty.Register("SomeString", typeof(string), typeof(ownerclass), new UIPropertyMetadata(0));

    public string SomeString
    {
        get { return (string)GetValue(SomeStringProperty); }
        set { SetValue(SomeStringProperty, value); }
    }

    public MyControl()
    {
        InitializeComponent();
        DataContext = this;
    }
}

Тогда в вашем XAML:

<TextBlock Text="{Binding Path=SomeString}" />
Другие вопросы по тегам