Пользовательский интерфейс WPF не обновляется при изменении коллекции типов ConcurrentBag
У меня есть коллекция, которая привязана к сетке данных в пользовательском интерфейсе WPF.
Мое требование таково, что мне нужно обновлять значение свойства 10 раз в секунду для каждого элемента в коллекции.
Итак, я взял коллекцию типов ConcurrentBag. После обновления значения для каждого элемента. Я запускаю RaisePropertyChange явно. Но интерфейс не меняется.
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (stockCollection != null)
{
stockCollection.ToList().ForEach((s) => s.Price = DateTime.Now.Millisecond);
Action raiseStockCollectionProperty = new Action(() => RaisePropertyChangedEvent("StockCollection"));
Dispatcher.BeginInvoke(raiseStockCollectionProperty);
}
}
2 ответа
Я не думаю, что предыдущий ответ даст решение вашей проблемы. Фактически вы вообще не обновляете коллекцию: вы обновляете свойство всех экземпляров Stock в коллекции. Обновление коллекции означает добавление или удаление элементов в ней. Поскольку семантика различна, возможно, связанный элемент управления не будет проверять свойства уже существующих объектов в коллекции при запуске события CollectionChanged. Это была бы разумная оптимизация.
Я бы посоветовал вам реализовать INotifyPropertyChange в вашем классе Stock и запустить событие propertyChanged здесь (однако, в хорошем потоке, используя Dispatcher) в установщике свойства Price.
private DateTime _price;
public DateTime Price
{
get
{
return _price;
}
set
{
if(_price!=value)
{
_price = value;
RaisePropertyChanged("Price");
}
}
}
protected void RaisePropertyChanged(string property)
{
var propertyChanged = PropertyChanged;
if(propertyChanged!=null)
{
propertyChanged(this,new PropertyChangedEventArgs(property));
}
}
РЕДАКТИРОВАТЬ: Я неправильно понял ваш вопрос, который на самом деле об обновлении свойства, а не об обновлении коллекции. Так что, если вы действительно хотите обновить Price
Соберите все предметы из вашей коллекции, затем Where
пункт примера ниже не поможет вам, конечно.
Вы на самом деле не изменяете свою коллекцию;)
stockCollection.ToList().ForEach((s) => s.Price = DateTime.Now.Millisecond);
Вы можете захотеть сделать:
stockCollection = new ConcurrentBag(stockCollection.Where(...));
РЕДАКТИРОВАТЬ:
Значит, мне нужно каждый раз создавать новый объект коллекции?
Как ваша коллекция не реализует INotifyCollectionChanged
ни INotifyPropertyChanged
, да. Я бы предложил использовать ObservableCollection
вместо вашего текущего типа коллекции, если это возможно. ObservableCollection
может уведомлять об обновлении свойства элемента, а также вызывать событие, когда элемент добавляется / удаляется.
ObservableCollection<YourType> myCollection = new ObservableCollection<YourType>();
...
public ObservableCollection<YourType> MyCollection
{
get
{
return this.myCollection;
}
set
{
if (value != this.myCollection)
{
this.myCollection = value;
this.RaisePropertyChanged("MyCollection");
}
}
}
...
// Following lines of code will update the UI because of INotifyCollectionChanged implementation
this.MyCollection.Remove(...)
this.MyCollection.Add(...)
// Following line of code also updates the UI cause of RaisePropertyChanged
this.MyCollection = new ObservableCollection<YourType>(this.MyCollection.Where(z => z.Price == 45));