Пользовательский интерфейс 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));
Другие вопросы по тегам