J.Meulenbeld
J.Meulenbeld

Reputation: 355

List<> propertychanged event

I am working on a project in which I need to notify my GUI that my list has new items.

I tried this with an observablecollection, but I use timers, and when I try to add or remove items from the observablecollection, then an exception is thrown that the collection is being marshalled from another thread.

Therefore, I started thinking about using the PropertyChanged event. However, I have trouble with getting it to work. What I understand is that it is used for properties. I have tried the following code without success:

public class MyCollection : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged;

    public ConcurrentQueue<PC_Info_Item> data;

    public List<string> table;

    public MyCollection()
    {
        data = new ConcurrentQueue<PC_Info_Item>();
        table = new List<string>();
    }

    public void Add(PC_Info_Item item)
    {
        data.Enqueue(item);
        OnPropertyChanged(nameof(table));
    }

    public void Add(string item)
    {
        table.Add(item);
        OnPropertyChanged(nameof(table));
    }

    public void delete()
    {
        data.TryDequeue(out PC_Info_Item item);
        OnPropertyChanged(nameof(table));
    }

    public void delete_string(string item)
    {
        table.Remove(item);
        OnPropertyChanged(nameof(table));
    }

    protected void OnPropertyChanged(string name = "")
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
    }
}

Is there a way to make this work for lists?

Upvotes: 1

Views: 775

Answers (2)

Mayur Saswade
Mayur Saswade

Reputation: 31

I think you should call on property changed as below where we should get the invocation list and call invoke on each receiver with lock.

private object _lock = new object();
protected void OnPropertyChanged(string name = "")
{
  var receivers = this.PropertyChanged.GetInvocationList();
  foreach (EventHandler<PropertyChangedEventArgs> receiver in receivers)
  {
    lock (this._lock)
    {
      receiver?.Invoke(this, new PropertyChangedEventArgs(name));
    }
  }
}

Upvotes: 1

moozywu
moozywu

Reputation: 229

you can wrap the calls into lock, that will make other threads wait till the call is finished.

    private readonly object CollectionLock = new object(); 
    
    public void Add(PC_Info_Item item)
    {
        lock(CollectionLock) {
            data.Enqueue(item);
        }
    }

    public void Add(string item)
    {
        lock(CollectionLock) {
            table.Add(item);
        }
    }

    public void delete()
    {
        lock(CollectionLock) {
            data.TryDequeue(out PC_Info_Item item);
        }
    }

    public void delete_string(string item)
    {
        lock(CollectionLock) {
            table.Remove(item);
        }
    }

Upvotes: 1

Related Questions