В моем приложении C#/WPF у меня есть класс с несколькими свойствами:
public class VariationDefinition
{
public int VariationsCount => Variations == null ? 0 : Variations.Count;
public ObservableCollection<ConditionVariation> Variations { get; private set; }
public void RegenerateVariations()
{
//Initializes and fills the Variations collection
//...
}
}
На стороне WPF есть несколько свойств, привязанных к этим свойствам, например:
<ListView ItemsSource = "{Binding Variations}"/>
<TextBlock Text = "{Binding VariationsCount}"/>
Когда вызывается RegenerateVariations
, ListView
немедленно обновляется, указывая, что привязка работает правильно. Однако TextBlock
не обновляется. Я предполагаю, что это связано с тем, что изменение в коллекции Variations
не вызывает событие NotifyPropertyChanged
в свойстве VariationsCount
.
Насколько я понимаю, можно подписаться на ObservableCollection<T>.CollectionChanged Event
(документы), но я не знаю, как прикрепить это к свойству VariationsCount
. Кажется, я не могу найти никаких примеров, но, вероятно, я ищу не то, что нужно. Можете ли вы объяснить, как это сделать?
Вместо создания другой переменной вы можете привязать свой код пользовательского интерфейса непосредственно к свойству Count
объекта ObservableCollection
, и он уведомит пользовательский интерфейс, когда счетчик изменится, как показано ниже.
<ListView ItemsSource = "{Binding Variations}"/>
<TextBlock Text = "{Binding Variations.Count}"/>
если вам не нравится этот подход, вы можете самостоятельно уведомить свой пользовательский интерфейс, сначала реализуя свой класс INotifyPropertyChanged
и подписавшись на событие изменения коллекции, как показано ниже.
public class VariationDefinition : INotifyPropertyChanged
{
public event PropertyChangedEventHandler? PropertyChanged;
public VariationDefinition()
{
// subscribe on collection change
Variations.CollectionChanged += (s, e) =>
{
// notify the UI that property VariationsCount is changed
// and UI will update the new value
PropertyChanged?.Invoke(this, new(nameof(VariationsCount)));
};
}
public int VariationsCount => Variations?.Count ?? 0;
public ObservableCollection<ConditionVariation> Variations { get; } = new();
}
Спасибо, это намного лучше, но что, если свойство, которому необходимо подписаться на CollectionChanged, принадлежит другому классу, о котором VariationDefinition не должно знать? Можно ли как-то подписаться на это событие извне или предоставить общедоступную функцию в VariationDefinition, которая включает позднюю подписку?
VariationDefinition
заботится о своем свойстве и изменениях в нем и уведомляет внешний мир через событие PropertyChanged
.... в другом смысле, если какой-либо код снаружи VariationDefinition
заботится об изменении свойства в VariationDefinition
, он может подписаться на событие PropertyChanged
, которое исходит из INotifyPropertyChanged
интерфейса. .. Пользовательский интерфейс автоматически подписывается на это событие
Рекомендую вам прочитать эту статью на Реагирование на изменения даст вам больше информации о INotifyPropertyChanged
Привязка к свойству ObservableCollection.Count
, как предполагалось изначально, является лучшим решением.
@BionicCode Я тоже того же мнения
@JustinasRubinovas, если это решение не решает вашу проблему, обновите вопрос и добавьте дополнительную информацию о том, какой именно сценарий вы пытаетесь решить.
Просто имейте в виду, что замена элемента в коллекции не приведет к изменению его счетчика, поэтому я бы сказал, что прикрепление обработчика CollectionChanged — это то, что вам обычно следует делать для обновления зависимых свойств. Count — это всего лишь простой частный случай.
Большое спасибо. Ваш ответ работает для сценария, который я опубликовал, и я проверил другие ваши предложения - они тоже работают. @Клеменс, спасибо и тебе за совет, мне обязательно нужно об этом подумать.
Спасибо, в этом случае это, похоже, работает (нулевые вариации, похоже, не нарушают его), но могут быть и другие случаи, когда свойству может потребоваться сделать что-то более сложное, чем просто предоставление счетчика, особенно если это свойство принадлежит другому классу и должен следить за изменениями в этой коллекции.