#c# #wpf #binding
#c# #wpf #привязка
Вопрос:
У меня ситуация, когда я загружаю список объектов из базы данных SQL. Для каждого из объектов я хочу отобразить a CheckBox
в an ItemsControl
и IsChecked
привязать его свойство к true
тогда и только тогда, когда элемент окна DataContext
содержит этот объект в списке.
Давайте назовем мое окно MyWindow
. Of — DataContext
MyWindow
это объект типа MyContext
, который имеет список объектов (загруженных из базы данных) типа DataObject
и объект типа Item
:
public class MyContext {
public Item CurrentItem { get; set; }
public List<DataObject> Data { get; set; }
}
public class Item {
public List<DataObject> CheckedDataObjects { get; set; }
}
У MyWindow.xaml
меня есть мой ItemsControl
, который привязан к Data
списку. ItemTemplate
Определяет, что каждый DataObject
из них должен отображаться с a CheckBox
, который должен иметь IsChecked
привязку к true тогда и только тогда, когда конкретное DataObject
содержится в MyWindow.DataContext.CurrentItem.CheckedDataObjects
.
Моя лучшая идея — использовать IMultiValueConverter
подход, однако я получаю XamlParseException
с внутренним InvalidOperationException
, говоря, что для двусторонней привязки требуется Path или XPath (свободно переведенный). Пожалуйста, сообщите!
<ItemsControl ItemsSource="{Binding Data}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<CheckBox>
<CheckBox.IsChecked>
<MultiBinding Converter="{StaticResource MyItemHasDataObjectConverter}">
<Binding RelativeSource="{RelativeSource FindAncestor, AncestorType={x:Type local:MyWindow}}" Path="DataContext.CurrentItem"/>
<Binding RelativeSource="{RelativeSource Self}"/>
</MultiBinding>
</CheckBox.IsChecked>
</CheckBox>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
public class ItemHasDataObjectConverter : IMultiValueConverter {
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture) {
// values should contain two objects: the CurrentItem object and an object of type DataObject
if (values.Length == 2 amp;amp; values[0] is Item amp;amp; values[1] is DataObject) {
return (values[0] as Item).CheckedDataObjects.Contains(values[1] as DataObject);
}
return false;
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture) {
return null;
}
}
Редактировать
После приведенного ниже ответа Aabid конвертер теперь, похоже, работает правильно. Кроме того, я добавил Checked
Unchecked
обработчики событий и к CheckBox
объектам, из которых добавляется / удаляется соответствующий DataObject
объект CurrentItem.CheckedDataObjects
. Однако, если я выполняю сброс CurrentItem.CheckedDataObjects
с помощью кода, либо путем вызова Clear()
, либо путем настройки CheckedDataObjects = new List<DataObject>()
, CheckBox
он не обновляется в пользовательском интерфейсе (они остаются проверенными).
Я убедился, что оба MyContext
и Item
реализуют INotifyPropertyChanged
и запускают соответствующие OnPropertyChanged
методы.
Ответ №1:
Добавьте свойство Path=DataContext к вашей второй привязке в вашей многозначной привязке, т.е.
<Binding Path=DataContext RelativeSource="{RelativeSource Self}"/>
Комментарии:
1. Спасибо за ваш ответ! Теперь конвертер, похоже, получает правильные входные объекты. Я также добавил обработчики событий для
Checked
иUnChecked
для флажков, которые добавляют / удаляют соответствующийDataObject
объектCurrentItem.CheckedDataObjects
. На самом деле, единственное, что, похоже, сейчас не работает, — это если я делаюCheckedDataObjects.Clear()
илиCheckedDataObjects = new ...
в коде позади, тогда он не обновляет флажки в пользовательском интерфейсе (они остаются отмеченными). Есть идеи?2. При очистке списка соответствующие измененные события коллекции не запускаются, чтобы сообщить пользовательскому интерфейсу об обновлении. Использование наблюдаемой коллекции вместо списка поможет вам в этом отношении. Кроме того, вы привязали элемент управления items к данным, а не к CheckedDataObjects. Очистка или переназначение, которые не приведут к обновлению вашей коллекции данных.
3. Спасибо. На самом деле, я использовал ObservableCollection, но последняя часть вашего комментария исправила это!