silverlight — привязка к двум объектам

#data-binding #silverlight-4.0

#привязка к данным #silverlight-4.0

Вопрос:

Я хочу создать пользовательский элемент управления, который может быть привязан к некоторым данным, предоставленным извне элемента управления (требование A), а некоторые свойства XAML должны быть привязаны к свойствам самого элемента управления (требование B).

Допустим, у меня есть класс данных с именем StudentData и элемент управления с именем StudentControl. Я использую этот элемент управления внутри сетки данных. Я поместил StudentControl в сетку с DataGridTemplateColumn. Я каким-то образом привязываю StudentData в текущей ячейке к элементу управления. Это требование A. Этот StudentControl хочет указать, доступны ли для редактирования некоторые элементы управления внутри него или нет. Лучший способ сделать это — предоставить свойство, такое как StudentControl .Доступно для редактирования с помощью функции контроля. Затем я могу привязать свойство IsEnabled этих элементов управления к этому свойству. Это требование B.

Вот моя первая идея. Я привязываю текущие StudentData к DP StudentControl, затем внутри StudentControl я меняю контекст данных на сам элемент управления:

 <UserControl DataContext="{Binding RelativeSource={RelativeSource Self}}">
  <TextBox
    Content="{Binding Path=ExposedStudentData.Field1}" *reqA*
    IsEnabled="{Binding Path=OtherProperty1}" /> *reqB*
</UserControl>
  

Я понял, что таким образом StudentControl получает StudentData извне, предоставляет эти же StudentData и другие новые свойства (таким образом, данные и другие свойства теперь находятся в одном месте, а не в двух), а затем я могу привязаться к этим открытым свойствам в XAML (reqA reqB выполняются одновременно). За исключением того, что это не работает из-за этой ошибки. В принципе, если я задаю DataContext элемента управления самому себе, то он устанавливается до применения внешней привязки. Итак, если мой путь привязки внутри ячейки равен X, а затем контекст данных изменяется, механизм привязки будет искать X в новом контексте собственных данных, а не во внешнем контексте данных сетки.

Вот моя вторая идея. Я привязываю текущие StudentData к DataContext или DP StudentControl. Затем, чтобы получить доступ к другим открытым свойствам StudentControl, я даю имя UserControl и использую привязку ElementName:

 <UserControl x:Name="self">
  <TextBox
    Content="{Binding Path=Field1}" *reqA*
    IsEnabled="{Binding ElementName=self, Path=OtherProperty1" /> *reqB*
</UserControl>
  

Таким образом, я понял, что текущим контекстом данных является StudentData, и он не изменен, и я могу привязаться к нему с помощью простого пути (reqA), и я могу привязаться к другим открытым свойствам с помощью материала ElementName (reqB). Это работает в базовых сценариях, но не в DataGrid из-за этой ошибки. Я предполагаю, что проблема возникает, когда в визуальном дереве есть несколько элементов управления с одинаковым именем.

Я действительно начинаю ненавидеть Silverlight, я начал использовать его месяц назад, и я уже сообщил о 9 ошибках. Всякий раз, когда я пытаюсь создать что-то отличное от простого приложения hello World или чего-то, для чего Microsoft и все остальные, похоже, используют Silverlight, я сталкиваюсь с новой ошибкой. И что теперь, как бы вы привязались к классу данных, заданному извне элемента управления, и некоторым другим свойствам, предоставляемым элементом управления одновременно? Без, конечно, настройки привязок из кода (что я делаю сейчас, но это кошмар со списками и таблицами данных) или без использования привязки вообще.

Ответ №1:

Я думаю, что ваша проблема связана с DataContext и тем, как он наследуется, а также с областями имен.

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

Что касается вашей второй проблемы, если вы находитесь внутри DataTemplate, вы находитесь в другой области имен, чем за ее пределами. Вы не можете получить доступ к элементам управления «по имени» за пределами DataTemplate. Что вы можете сделать здесь (для Silverlight 4 и ниже), так это самостоятельно просмотреть визуальное дерево и найти нужный вам элемент управления. Это, однако, станет намного проще и менее болезненным с некоторыми новыми функциями в SL5, в частности, с функцией «FindAncestor» (которая уже существует в WPF).

Вот статья на MSDN о Namescopes в Silverlight. И вот еще один вопрос о привязке данных, в котором упоминается, как наследуется DataContext.

Я думаю, этот пост в блоге должен помочь вам достичь того, что вы ищете. В нем показано, как реализовать в Silverlight поведение, подобное «Привязке к RelativeSource с помощью FindAncestor».

Надеюсь, это поможет 🙂

Ответ №2:

На другом форуме мне сказали использовать MVVM. Как оказалось, это может немного улучшить мою первую идею. Вместо привязки моего StudentControl к StudentData, а затем предоставления этих данных и других свойств, я должен создать viewmodel, скажем StudentControlData , который содержит StudentData и дополнительные свойства, требуемые элементом управления. Если я привяжу свой элемент управления к этому, то в контексте унаследованных данных элемента управления у меня будет доступ ко всем свойствам, которые мне нужны. Теперь осталась единственная проблема в том, что внутри ListBox в моем StudentControl я теряю этот контекст данных.

Комментарии:

1. Как я уже сказал в моем приведенном выше ответе, главное, чего мне не хватало, это MVVM. Но для моего шаблона listbox мне это тоже было нужно.