Связывание 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
объекты, вы все равно можете использовать любой метод - однако, если вы хотите иметь возможность привязки к этим свойствам, они должны быть определены как DependencyProperty
s.
Можете ли вы обновить свой пост любым источником, чтобы мы могли его найти?
Оригинальный ответ:
Я не совсем уверен, что понимаю вашу конечную цель, но самый ленивый способ указать 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}" />