Привязка динамического списка проверенных свойств флажков

#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, но последняя часть вашего комментария исправила это!