简体   繁体   中英

Update UI on added item to collection changed

I'm using an ObservableCollection that is later on supposed to be filled with data coming in from a COM port, meaning it will be updated a lot. For testing purposes I setup design time sample data (which works fine) and runtime sample data, however I can't get my UI to update when adding items to my collection. I already managed to implement INotifyPropertyChanged succesfully in my class that looks like this:

public class SensorViewModel : INotifyPropertyChanged
{
    public SensorViewModel()
    {
        dataItems = new ObservableCollection<SensorData>();
        dataItems.CollectionChanged += dataItems_CollectionChanged;
    }

    private ObservableCollection<SensorData> _dataItems;
    public ObservableCollection<SensorData> dataItems
    {
        get { return _dataItems; }
        set
        {
            _dataItems = value;
            // notify of changes
            NotifyPropertyChanged("dataItems");
            NotifyPropertyChanged("lastItem");
        }
    }

    public SensorData lastItem
    {
        get { return dataItems.Last(); }
    }

    public void LoadData()
    {
        dataItems.Add(new SensorData { id = 0, accelX = 0.231, accelY = 0.345, accelZ = -1.234 });
        dataItems.Add(new SensorData { id = 1, accelX = 1.231, accelY = 1.345, accelZ = -0.234 });
    }

    // handle property changes
    public event PropertyChangedEventHandler PropertyChanged;
    private void NotifyPropertyChanged(string propertyName)
    {
        var handler = this.PropertyChanged;
        if (handler != null)
            handler(this, new PropertyChangedEventArgs(propertyName));
    }

    void dataItems_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
    {
        // get the sender observable collection
        ObservableCollection<string> obsSender = sender as ObservableCollection<string>;

        List<SensorData> editedOrRemovedItems = new List<SensorData>();

        if (e.NewItems != null)
        {
            foreach (SensorData newItem in e.NewItems)
            {
                editedOrRemovedItems.Add(newItem);
            }
        }

        if (e.OldItems != null)
        {
            foreach (SensorData oldItem in e.OldItems)
            {
                editedOrRemovedItems.Add(oldItem);
            }
        }

        // get the action which raised the collection changed event
        NotifyCollectionChangedAction action = e.Action;
    }
}

I create the DataContext on the MainWindow.xaml.cs and call LoadData() after that. However on my separate page called AccelData.xaml (subtab using ModernUI WPF project) the binding won't update. I'm binding it with {Binding lastItem.accelX} .

Do I need to somehow copy over the DataContext from the MainWindow to the subpage or am I simply not using the CollectionChanged event right? I just can't seem to get my binded value to appear at runtime.

You explicitly need to raise PropertyChanged event for lastItem in case you want it to be refreshed on UI.

Do it from collectionChanged handler:

void dataItems_CollectionChanged(object sender, 
                                 NotifyCollectionChangedEventArgs e)
{
   ......
   NotifyPropertyChanged("lastItem");
}

Also your collectionChanged handler is not making any sense to me. Adding items in list and not using it anywhere.

Moreover obsSender will always be null because sender collection is of type ObservableCollection<SensorData> but your are typecasting it to ObservableCollection<string> .

// get the sender observable collection (THIS WILL BE NULL ALWAYS)
ObservableCollection<string> obsSender = sender as ObservableCollection<string>;

Three things:

  1. I do not understand what you are doing in your CollectionChanged event. You are creating list and assigning items to that list and then doing nothing so your list is lost. Is this your intention?

  2. I think you should change your binding. Instead of {Binding Path=lasItem.accelX} do something like: DataContext={Binding lastItem} Property(for example Text)={Binding accelX} .

  3. And I think there's another possible bug with your code:

    dataItems.CollectionChanged += dataItems_CollectionChanged;

You are assigning event handler only once. When you are changing your ObservableCollection(what is possible because of public setter) you should remove event handler from old object and add event handler to new one. Something like:

private ObservableCollection<SensorData> _dataItems;
public ObservableCollection<SensorData> dataItems
{
      get { return _dataItems; }
      set
      {
          if(_dataItems != null ) _dataItems.CollectionChanged -= dataItems_CollectionChanged;
          _dataItems = value;
          if(_dataItems != null ) _dataItems.CollectionChanged += dataItems_CollectionChanged;
          // notify of changes
          NotifyPropertyChanged("dataItems");
          NotifyPropertyChanged("lastItem");
      }
 }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM