WPF/C# 将 ObservableCollection 中项目的属性更改更新到 ListBox

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/18731608/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-10 13:03:21  来源:igfitidea点击:

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

c#wpflistboxobservablecollection

提问by B.K.

I have a list box:

我有一个列表框:

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

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

从这个修改过的 Observable 集合中获取它的数据:

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.

它是在使用 FileSystemWatcher 监视特定文件夹以添加、删除和修改文件的类中创建的。

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):

ObservableCollection 被修改(因此最后是 Ex),以便我可以从外部线程修改它(代码不是我的,我实际上在这个网站上做了一些搜索并找到了它,就像一个魅力):

    // 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.

我如何将 FileItem 的属性更改通知列表框?我认为 ObservableCollection 会处理这个问题,但显然它只有在添加或删除 FileItem 时才会引发标志,而不是在其内容发生变化时。

采纳答案by Anand Murali

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

你的FileItem班级应该实现INotifyPropertyChanged. 下面是它的一个简单的工作实现。

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


}

回答by New Dev

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

这就是ObservableCollection工作原理 - 它仅监控项目的插入/删除/移动。

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

要在每个项目(或FileItem在您的情况下)更改时更新视图,FileItem必须INotifyPropertyChanged在您设置要观察的每个属性时实现并触发适当的事件。

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

以下是如何执行此操作的示例:http: //msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged.aspx

回答by Berezh

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
}