从另一个线程更新ObservableCollection的最佳/最清洁策略 [英] Best/cleanest strategy to update an ObservableCollection from another thread

查看:181
本文介绍了从另一个线程更新ObservableCollection的最佳/最清洁策略的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

通常,我检查是否可以访问ObservableCollection,如果没有,我会呼叫Dispatcher.这里(在Stackoverflow上)还有其他一些解决方案,但是我不知道什么是最好和最干净的方法.我认为我的解决方案已过时,不应再使用.

Normally I check if I have access to the ObservableCollection and if not, I call a Dispatcher. Here (on Stackoverflow) are also some other solutions, but I don't know what is the best and cleanest way. I think my solution is obsolete and should not be used anymore.

是绑定到UIItemsCollection. _UpdateTheCollectionFromAnotherThread()将被调用(从另一个thread或打开另一个thread)并将数据临时保存到items.之后,我将检查访问权限,并在需要时调用dispatcher.

In my example is the ItemsCollection bound to the UI. The _UpdateTheCollectionFromAnotherThread() would being called (from another thread or would open another thread) and save the data temporary to items. After that I would check the access and call a dispatcher if needed.

这是我必须走的路吗?还是有一些更好,更清洁的解决方案?

Is this the way I have to go or are there some better and cleaner solutions?

public class FooClass
{
    // ##############################################################################################################################
    // Properties
    // ##############################################################################################################################

    /// <summary>
    /// This Items are bound to my UI.
    /// </summary>
    public ObservableCollection<string> ItemsCollection { get; } = new ObservableCollection<string>();

    // ##############################################################################################################################
    // Singleton pattern
    // ##############################################################################################################################

    /// <summary>
    /// The instance of <see cref="FooClass"/>.
    /// </summary>
    internal static FooClass Instance => _Instance ?? (_Instance = new FooClass());
    private static FooClass _Instance;

    // ##############################################################################################################################
    // Konstruktor
    // ##############################################################################################################################

    private FooClass()
    {

    }


    // ##############################################################################################################################
    // Method
    // ##############################################################################################################################

    private void _UpdateTheCollectionFromAnotherThread()
    {
        List<string> items = new List<string>();

        //Here would be some logic to create and fill the items list....


        //and now apply them to the public list

        if (System.Windows.Application.Current.Dispatcher.CheckAccess())
        {
            ItemsCollection.Clear();
            foreach (string item in items)
            {
                ItemsCollection.Add(item);
            }
        }
        else
        {
            System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() =>
            {
                ItemsCollection.Clear();
                foreach (string item in items)
                {
                    ItemsCollection.Add(item);
                }
            }));
        }
    }
}

推荐答案

如果您使用的是.NET Framework 4.5或更高版本,则可以通过调用BindingOperations.EnableCollectionSynchronization方法启用跨多个线程访问该集合的功能.请注意,必须在UI线程上调用此方法:

If you are on .NET Framework 4.5 or later you can enable the collection to be accessed across multiple threads by calling the BindingOperations.EnableCollectionSynchronization method. Note that this method must be called on the UI thread:

public class FooClass
{
    private readonly object _lock = new object();
    public ObservableCollection<string> ItemsCollection { get; } = new ObservableCollection<string>();

    internal static FooClass Instance => _Instance ?? (_Instance = new FooClass());
    private static FooClass _Instance;

    private FooClass()
    {
        BindingOperations.EnableCollectionSynchronization(ItemsCollection, _lock);
    }

    private void _UpdateTheCollectionFromAnotherThread()
    {
        List<string> items = new List<string>();
        ItemsCollection.Clear();
        foreach (string item in items)
        {
            ItemsCollection.Add(item);
        }
    }
}

如果FooClass可能是在后台线程上创建的,那么您可以通过不重复自己的方式来改善代码:

If the FooClass may be created on a background thread, you might still improve your code a bit by not repeating yourself:

public class FooClass
{
    public ObservableCollection<string> ItemsCollection { get; } = new ObservableCollection<string>();

    internal static FooClass Instance => _Instance ?? (_Instance = new FooClass());
    private static FooClass _Instance;

    private FooClass() { }

    private void _UpdateTheCollectionFromAnotherThread()
    {
        List<string> items = new List<string>();

        if (System.Windows.Application.Current.Dispatcher.CheckAccess())
            ClearCollection(items);
        else
            System.Windows.Application.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(() => ClearCollection(items)));
    }

    private void ClearCollection(List<string> items)
    {
        ItemsCollection.Clear();
        foreach (string item in items)
        {
            ItemsCollection.Add(item);
        }
    }
}

这篇关于从另一个线程更新ObservableCollection的最佳/最清洁策略的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆