从另一个线程

时间:2017-06-30 06:35:48

标签: c# wpf multithreading observablecollection dispatcher

通常情况下,我会检查是否可以访问ObservableCollection,如果没有,我会调用Dispatcher。这里(Stackoverflow)也是其他一些解决方案,但我不知道什么是最好和最干净的方法。我认为我的解决方案已经过时,不应再使用了。

在我的示例中,ItemsCollection绑定到UI_UpdateTheCollectionFromAnotherThread()将被调用(来自另一个thread或将打开另一个thread)并将数据临时保存到items。之后,我会检查访问权限并在需要时拨打dispatcher

这是我必须去的方式还是有更好更清洁的解决方案?

FooClass

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

2 个答案:

答案 0 :(得分:4)

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

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,您可能仍然可以通过不重复自己来改进您的代码:

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

答案 1 :(得分:0)

我无法判断您是否在此处实施MVC或MVW模式,但即使使用桌面应用,这也是一种很好的做法。

因此我认为ObservableCollection是视图的一部分,而不是模型,因为它通常不是功能模型所必需的,而是用于WPF UI绑定。 我说这个的主要原因是它是可变的&amp;它与WPF交互的整个方式依赖于可变性。

我没有_UpdateTheCollectionFromAnotherThread,因为你应该避免从另一个线程更新UI。 这样做通常意味着您的设计中存在模型 - 视图 - 控制器角色的混合。

相反,在模型中执行所有异步/多线程内容,因为这是处理大量处理的地方。

然后,在UI线程中使用模型更新UI更简单。