Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 具有Rx和ObservableCollection的线程安全性_C#_Wpf_Thread Safety_Observablecollection_System.reactive - Fatal编程技术网

C# 具有Rx和ObservableCollection的线程安全性

C# 具有Rx和ObservableCollection的线程安全性,c#,wpf,thread-safety,observablecollection,system.reactive,C#,Wpf,Thread Safety,Observablecollection,System.reactive,为了寻求更具响应性的方式,用大量的项目更新列表框,我转向了Rx。这是我对它的实现: ObservableCollection<FileData> _fileCollection = new ObservableCollection<FileData>(); public ObservableCollection<FileData> FileCollection { get { return _fileCollection; } } pu

为了寻求更具响应性的方式,用大量的项目更新列表框,我转向了Rx。这是我对它的实现:

    ObservableCollection<FileData> _fileCollection = new ObservableCollection<FileData>();
    public ObservableCollection<FileData> FileCollection { get { return _fileCollection; } }
    public static object _fileCollectionLock = new object();

    public Subject<FileData> subject = new Subject<FileData>();

    public MainWindow( )
    {
        InitializeComponent();
        BindingOperations.EnableCollectionSynchronization(_fileCollection, _fileCollectionLock);
        UpdateFileList(subject);
    }

    private void UpdateFileList(IObservable<FileData> sequence)
    {
        sequence.Subscribe(value=>_fileCollection.Add(value));
    }

    private void ListFiles(string fullpath)
    { 
        _fileCollection.Clear(); //crashed once
        Task.Factory.StartNew(() =>
        {
            DirectoryInfo info = new DirectoryInfo(fullpath);
            IEnumerable files = info.EnumerateFiles(Filter + "*", SearchOption.TopDirectoryOnly,true);
            foreach (FileInfo file in files)
            {
                ...
                FileData fd = new FileData(filename, filedate, filesize, fileext);      
                subject.OnNext(fd);
observetecollection\u fileCollection=newobservetecollection();
public observeCollection FileCollection{get{return\u FileCollection;}}
公共静态对象_fileCollectionLock=新对象();
公共主题=新主题();
公共主窗口()
{
初始化组件();
BindingOperations.EnableCollectionSynchronization(\u fileCollection,\u fileCollectionLock);
更新列表(主题);
}
私有void UpdateFileList(IObservable序列)
{
sequence.Subscribe(value=>\u fileCollection.Add(value));
}
私有void列表文件(字符串完整路径)
{ 
_fileCollection.Clear();//崩溃一次
Task.Factory.StartNew(()=>
{
DirectoryInfo=新的DirectoryInfo(完整路径);
IEnumerable files=info.EnumerateFiles(Filter+“*”,SearchOption.TopDirectoryOnly,true);
foreach(文件中的文件信息文件)
{
...
FileData fd=新的FileData(文件名、filedate、filesize、fileext);
主题.OnNext(fd);
有一次,在我的代码中,_fileCollection.Clear();(对不起,忘记了错误)。
我需要使用锁吗?在何处?

您的实现存在一些问题,根源在于对如何正确使用EnableCollectionSynchronization的误解。不过,老实说,我并不感到惊讶-它的文档记录很差,设计也不太好(我怀疑主要是因为必须在不破坏更改的情况下使其与WPF一起工作)

正确使用
EnableCollectionSynchronization
我将简要介绍正确的用法:

EnableCollectionSynchronization
注册一个锁,WPF将在需要访问该集合时(例如,当控件枚举它时)使用该锁

在.NET 4.5中,后台线程(即不是调用
EnableCollectionSynchronization
的线程)上引发的集合更改事件将排队并编组到UI线程

重要的是,使用此方法时,您仍然必须使用您在
EnableCollectionSynchronization
中注册的同一个锁自己锁定对集合的任何访问。特别是,您的代码中没有任何内容阻止
Clear()
Add()同时运行
这无疑是您看到的异常的原因

调用
EnableCollectionSynchronization
的一个好地方是从处理程序调用
BindingOperations.CollectionRegistrating
事件,它保证在创建任何
CollectionView
实例之前进行调用

更新UI绑定集合的最佳实践 综上所述,我认为您应该完全放弃这种方法——最好是承诺只更新UI线程上的UI绑定集合。RX非常适合这样做,您可以使用
ObserveOn
()如果你这样做,你就不必再担心同步对集合的访问,你的生活就会简单得多

我的建议是——尽可能地找出后台线程需要哪些更新,但修改UI线程本身的集合。这种方法几乎总是足够快,如果不是,你可能需要考虑你的设计

查看讨论和有关UI更新的文章链接

另外,还可以查看关于UI线程上发生大量更改的问题的另一个讨论/分析,以及如何缓冲大量更改以避免占用调度程序


还值得一看框架。

你在哪里调用ListFiles?@MichalCiechan我从文件夹中调用它单击,从刷新按钮…我删除了“async”关键字,如果这让人困惑,因为它并不重要。你在_fileCollection.Add(value)上不总是遇到跨线程访问冲突吗?@MichalCiechan在使用时没有,但现在我尝试调用多个文件夹的Listfiles,得到“System.ArgumentOutOfRangeException:插入索引超出范围”没有将我指向异常位置。即使在那时,也不会每次都发生。我理解答案的第一部分,并看到了我的问题。我查看了第二部分中所有链接的代码,但我不确定它是否能保证更好的性能。我运行了一些旧版本的代码,并注意到我没有从R中获得太多好处x和TaskFactory与.Add(fd)的比较UI线程上的所有内容。枚举或GetFiles需要0毫秒,所以我认为瓶颈是在添加所有项后更新列表框。在此期间,我甚至抑制了NotifyPropertyChange,没有任何差异。所有项都有很多绑定到FileData类中的不同数据,所以他可能是itI。如果Rx做得更快,我会非常惊讶。它添加了代码,因此应该会使事情变得更慢。它的好处是使某些编码问题变得更容易,而不是提高性能。它可以帮助用户界面在协调后台任务时保持响应,并使用户体验事件的反应更容易。当然,如果你可以使用简单的代码来实现目标,那么就去做吧它!谢谢你,詹姆斯!我从你的帖子中学到了很多,并通过将所有内容保留在UI线程上修复了崩溃问题。临时完成等待任务。之前延迟(1)。添加(fd)在循环中可以防止动画出现口吃。如果你有更好的解决方案,请让我知道。我的第一反应是我不喜欢这样-这不是我的自然选择…但如果它有效,为什么不呢?它很简单。它的作用是给WPF时间,让WPF根据每次更改的结果更新UI。请密切注意。如果有可能的话你可以