ItemsSource и коллекции, в которых изменяются только свойства элемента - PullRequest
0 голосов
/ 10 октября 2011

У меня горе с ComboBox, не отражающим изменения в свойствах коллекции, к которой привязан его ItemsSource.

Существует дерево, состоящее из наблюдаемой коллекции категорий объектов Category, содержащих объекты Setting.,Некоторые параметры определяют имена презентаций для домена значений, разрешенных для других параметров.Они распределены по нескольким категориям, но небольшое волшебство с LINQ создает ObservableCollection, в котором ChannelCategory предоставляет свойства ChannelNumber и ChannelTitle.

ChannelCategory.ChannelTitle - это StringSetting, ChannelNumber - это int, неизменяемое значение идентификатора, для которого ChannelTitleпредоставляет строку отображения.Опуская обильные, но не относящиеся к делу другие узлы, мы имеем следующее:

Channels
  ChannelCategory
    ChannelNumber = 1
    ChannelTitle = "caption for channel one"
  ChannelCategory
    ChannelNumber = 2
    ChannelTitle = "caption for channel two"
  ChannelCategory
    ChannelNumber = 3
    ChannelTitle = "caption for channel three"
...

Эта коллекция каналов подготовлена ​​и представлена ​​свойством класса, созданного и добавленного в словарь ресурсов окна в XAML (доступный как StaticResource),Такое расположение позволяет мне декларативно привязывать комбинированный список к каналам

    <ComboBox VerticalAlignment="Center" Grid.Column="2" 
              ItemsSource="{Binding Source={StaticResource cats}, Path=Channels}"
              DisplayMemberPath="ChannelTitle.Editor"
              SelectedValuePath="ChannelNumber"
              SelectedValue="{Binding Editor}"
              />

. Все это работает, но изменения в другом месте значения ChannelTitle не отражаются в значениях, показанных в списке комбинированного списка.

Различные хитрости отладки с точками останова и событием DropDownOpened позволили мне убедиться, что обновления доступны из коллекции, на которую ссылается ItemsSource.

И, наконец, мы дошли до тайны.Почему комбинированный список не обнаруживает изменений в элементах коллекции?Сама коллекция является ObservableCollection, поэтому она должна уведомлять об изменениях свойств.

Все элементы коллекции - это ChannelCategory, который является DependencyObject, а ChannelCategory.ChannelTitle является DependencyProperty.

I думаю, что проблема в том, что я не добавляю и не удаляю элементы из коллекции, поэтому, что касается коллекции, она имеет те же элементы и, следовательно, не изменилась.

Может кто-нибудь предложитьстратегия создания изменений в ChannelTitle, чтобы коллекция каналов уведомляла об изменениях, поэтому выпадающий список обновляется?


Предложение Рэйчел закончилось, как показано ниже.В контексте моего приложения это было значительно сложнее, поскольку каждая ChannelCategory владеет коллекцией объектов настроек, поэтому изменяемое значение является свойством объекта в коллекции, который является свойством объекта в коллекции, к которому привязан ItemsSource,Но суть предложения Рэйчел просто требовала применения на двух уровнях.

public class ObservableChannelCollection : ObservableCollection<ChannelCategory>
{
  protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
  {
    if (e.NewItems != null)
      foreach (ChannelCategory channel in e.NewItems)
        channel.PropertyChanged += channel_PropertyChanged;
    if (e.OldItems != null)
      foreach (ChannelCategory channel in e.OldItems)
        channel.PropertyChanged -= channel_PropertyChanged;
    base.OnCollectionChanged(e);
  }
  void channel_PropertyChanged(object sender, PropertyChangedEventArgs e)
  {
    OnPropertyChanged(e);
  }
}

1 Ответ

2 голосов
/ 10 октября 2011

ObservableCollection отслеживает изменения в самой Коллекции, такие как Add, Remove, Reset и т. Д., Но не отслеживает изменения отдельных элементов внутри коллекции.Поэтому, если вы обновите свойство элемента в ObservableCollection, коллекция не получит уведомление о том, что что-то изменилось.

Одна альтернатива - добавить событие к событию ObservableCollection.CollectionChanged, а при появлении новогодобавляются элементы, подключите изменение свойства к новым элементам, которое вызовет событие изменения коллекции.

void MyObservableCollection_CollectionChanged(object sender, CollectionChangedEventArgs e)
{
    if (e.NewItems != null)
    {
        foreach(MyItem item in e.NewItems)
        {
            MyItem.PropertyChanged += MyItem_PropertyChanged;
        }
    }

    if (e.OldItems!= null)
    {
        foreach(MyItem item in e.OldItems)
        {
            MyItem.PropertyChanged -= MyItem_PropertyChanged;
        }
    }
}

void MyItem_PropertyChanged(object sender, PropertyChange e)
{
    RaisePropertyChanged("MyObservableCollection");
}
...