Связывание DataContext с другим свойством в WPF - PullRequest
0 голосов
/ 30 августа 2011

Дело в том, что я всегда хочу привязать элементы управления к свойству 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 ]

1 голос
/ 02 сентября 2011

Я действительно не вижу причины для создания свойства, которое заменяет 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 объектом.Не создавайте какое-либо пользовательское свойство, которое люди должны помнить, чтобы связывать каждый раз, когда они хотят использовать ваш элемент управления.

1 голос
/ 30 августа 2011

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

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

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

{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 объектов вы все равно можете использовать любой метод - однако, если вы хотите иметь возможность привязки к этим свойствам, их нужно будет определить как DependencyProperty s.

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

<ч />

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

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

this.DataContext = this;

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

* +1054 * Пример:
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}" />
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...