B.K.
B.K.

Reputation: 10172

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

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.

Upvotes: 3

Views: 29680

Answers (3)

Berezh
Berezh

Reputation: 937

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
}

Upvotes: 1

Anand Murali
Anand Murali

Reputation: 4109

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));
    }


}

Upvotes: 12

New Dev
New Dev

Reputation: 49620

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

Upvotes: 6

Related Questions