WPF / C# Updating property change of an item in an ObservableCollection to the ListBox

28,241

Solution 1

Your FileItem class should implement INotifyPropertyChanged. Below is a simple working implementation of it.

public class FileItem : INotifyPropertyChanged
{
    private string _Name;

    public string Name
    {
        get { return _Name; }
        set {
            if (_Name != value)
            {
                _Name = value;
                OnPropertyChanged("Name");
            }
        }
    }

    private string _Path;

    public string Path
    {
        get { return _Path; }
        set {
            if (_Path != value)
            {
                _Path = value;
                OnPropertyChanged("Path");
            }
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    public void OnPropertyChanged(String propertyName)
    {
        if (PropertyChanged != null)
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
    }


}

Solution 2

That's how the ObservableCollection works - it monitors only insertion/deletion/moving of items.

To update the View when each item (or FileItem, in your case) changes, the FileItem must implement INotifyPropertyChanged and fire the appropriate event when you set each property that you want to observe.

Here's an example of how to do this: http://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

Solution 3

Try this simple one:

public class NotifyObservableCollection<TItem> : ObservableCollection<TItem>
    where TItem : class , INotifyPropertyChanged, new()
{
    #region Fields

    private Action _itemPropertyChanged;

    #endregion

    #region Constructor

    public NotifyObservableCollection(Action itemPropertyChanged)
    {
        _itemPropertyChanged = itemPropertyChanged;
    }

    #endregion

    #region Methods

    protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
    {
        if (e.Action == NotifyCollectionChangedAction.Add)
        {
            foreach (var item in e.NewItems)
            {
                var notifyItem = item as INotifyPropertyChanged;
                if (notifyItem != null)
                {
                    notifyItem.PropertyChanged += ItemPropertyChanged;
                }
            }
        }
        else if (e.Action == NotifyCollectionChangedAction.Remove)
        {
            foreach (var item in e.OldItems)
            {
                var notifyItem = item as INotifyPropertyChanged;
                if (notifyItem != null)
                {
                    notifyItem.PropertyChanged -= ItemPropertyChanged;
                }
            }
        }
        base.OnCollectionChanged(e);
    }

    #endregion

    #region Private Methods

    private void ItemPropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        if(_itemPropertyChanged!=null)
        {
            _itemPropertyChanged();
        }
    }

    #endregion
}
Share:
28,241
B.K.
Author by

B.K.

Software Engineer working in VR space.

Updated on November 06, 2020

Comments

  • B.K.
    B.K. over 3 years

    I have a list box:

    <ListBox x:Name="lbxAF" temsSource="{Binding}">
    

    that gets its data from this from this modified Observable Collection:

    public ObservableCollectionEx<FileItem> folder = new ObservableCollectionEx<FileItem>();
    

    which is created within a class that uses FileSystemWatcher to monitor a specific folder for addition, deletion and modification of files.

    The ObservableCollection was modified (hence the Ex at the end) so that I can modify it from an outside thread (code is not mine, I actually did some searching through this website and found it, works like a charm):

        // This is an ObservableCollection extension
        public class ObservableCollectionEx<T> : ObservableCollection<T>
        {
            // Override the vent so this class can access it
            public override event System.Collections.Specialized.NotifyCollectionChangedEventHandler CollectionChanged;
    
            protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
            {
                using (BlockReentrancy())
                {
                    System.Collections.Specialized.NotifyCollectionChangedEventHandler eventHanlder = CollectionChanged;
                    if (eventHanlder == null)
                        return;
    
                    Delegate[] delegates = eventHanlder.GetInvocationList();
    
                    // Go through the invocation list
                    foreach (System.Collections.Specialized.NotifyCollectionChangedEventHandler handler in delegates)
                    {
                        DispatcherObject dispatcherObject = handler.Target as DispatcherObject;
    
                        // If the subscriber is a DispatcherObject and different thread do this:
                        if (dispatcherObject != null && dispatcherObject.CheckAccess() == false)
                        {
                            // Invoke handler in the target dispatcher's thread
                            dispatcherObject.Dispatcher.Invoke(DispatcherPriority.DataBind, handler, this, e);
                        }
                        // Else, execute handler as is
                        else
                        {
                            handler(this, e);
                        }
                    }
                }
            }
        }
    

    The collection is made up of these:

    public class FileItem
    {
        public string Name { get; set; }
        public string Path { get; set; }
    }
    

    which allow me to store names and paths of files.

    Everything works great as far as deletion and addition of files, and the List Box gets updated flawlessly with respect to those two... however, if I change the name of any of the files, it doesn't update the list box.

    How would I notify list box of the changes in FileItem's properties? I assumed that ObservableCollection would handle that, but apparently it raises flag only when FileItem is added or deleted, not when its contents are changed.

  • B.K.
    B.K. almost 11 years
    How would I go about doing it? I was looking through MSDN documentation and I got extremely confused. I'm new to WPF and C#, but it's imperative that I get this to work.
  • B.K.
    B.K. almost 11 years
    Yeah, that's the one I was looking at. When I tried with mine, it didn't work. It actually was throwing some sort of an exception.
  • New Dev
    New Dev almost 11 years
    What's the exception? Since you mentioned something about updated from another thread, it could be that you get cross-thread access exception
  • B.K.
    B.K. almost 11 years
    I just looked at the code that AnandMurali provided and I was forgetting to add if (PropertyChanged != null) in OnPropertyChanged method.