简体   繁体   中英

WPF threadsave observable collection item change event

my application is a basic download app that allows users to download files from each other (a very basic kazaa :-))

Well for each download im displaying a progressbar and i want it updated according to the real download progress.

I have an observablecollection that holds a downloadInstance object which holds a progress property.

once i update the progress property the observablecollection change event probably isnt fired and the progressbar stays without any visual progress.

here is my threadsaveobservablecollection class

public class ThreadSafeObservableCollection<T> : ObservableCollection<T>
{
    public override event NotifyCollectionChangedEventHandler CollectionChanged;

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        NotifyCollectionChangedEventHandler CollectionChanged = this.CollectionChanged;
        if (CollectionChanged != null)
            foreach (NotifyCollectionChangedEventHandler nh in CollectionChanged.GetInvocationList())
            {
                DispatcherObject dispObj = nh.Target as DispatcherObject;
                if (dispObj != null)
                {
                    Dispatcher dispatcher = dispObj.Dispatcher;
                    if (dispatcher != null && !dispatcher.CheckAccess())
                    {
                        dispatcher.BeginInvoke(
                            (Action)(() => nh.Invoke(this,
                                new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset))),
                            DispatcherPriority.DataBind);
                        continue;
                    }
                }
                nh.Invoke(this, e);
            }
    }

}

This is the initialization process

uploadActiveInstances = new ThreadSafeObservableCollection<instance>();
instance newInstance = new instance() { File = file, User = user };
uploadActiveInstances.Add(newInstance);

and finally here is my instance class

public class instance
{
    public FileShareUser User { get; set; }
    public SharedFile File { get; set; }
    public int Progress { get; set; }
}

how can i raise the change event once a property of an instance changes (progress++) ?

The ObservableCollection will raise an event when IT changes (eg items are added/removed) but not when the items it holds change.

To raise an event when your items change, your instance class must implement the INotifyPropertyChanged interface.

For example:

public class instance : INotifyPropertyChanged
{
    private int progress;
    public int Progress 
    {
        get { return progress; }
        set
        {
            if (progress != value)
            {
                progress = value;
                if (PropertyChanged != null)
                {
                    PropertyChanged(this, new PropertyChangedEventArgs("Progress"));
                }
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    /* Do the same with the remaining properties */
    public string User { get; set; }
    public string File { get; set; }

}

You will see that now, when you change the progress it WILL get updated in the UI.
In the code above, since I don't raise the PropertyChanged event for User or File , they will not get updated in the UI when you change them.

Observablecollection updates the visual tree only when an item is being added or removed that's why when you change your item value it doesn't get re-rendered.

change the Progress property to be a dependency property and bind progress bar "Value" property or implement the INotifyPropertyChanged interface

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