从单独的线程访问ViewModel属性

时间:2011-12-15 17:35:39

标签: wpf mvvm

在我的wpf应用程序中,使用单独的线程调用viewmodel中的耗时操作。但是,此函数访问视图模型中绑定到视图中对象的多个属性。我尝试直接访问它们,我看不到有关它们归UI线程所有的投诉。我很想知道在线程之间直接使用它们的后果。

3 个答案:

答案 0 :(得分:5)

您可以从任何线程中自由使用ViewModel - 包括读写。一个主要的例外是处理集合 - 必须在用户界面线程上写入数据绑定集合,因为绑定不会自动封送到UI线程(就像简单的绑定一样)。

但是,您仍应考虑对任何写入进行适当的同步。正常的线程同步问题将会发生,因为ViewModel只是另一个类。

话虽如此,通常情况下,您希望处理同步的方式与在许多情况下略有不同。锁通常不在ViewModel上工作,因为WPF数据绑定不会锁定对象。因此,在ViewModel中需要同步时,通常应使用Dispatcher.Invoke / BeginInvoke来根据需要将回调编组回用户界面线程。

答案 1 :(得分:1)

除了通常的线程安全问题之外,没有任何后果。 VM特性通常存在问题的唯一问题是ObservableCollections,它具有线程关联性。

答案 2 :(得分:0)

如果你使用扩展你的ObservableCollection,你可以从一个单独的线程更新:

/// <summary>
/// Source: New Things I Learned
/// Title: Have worker thread update ObservableCollection that is bound to a ListCollectionView
/// http://geekswithblogs.net/NewThingsILearned/archive/2008/01/16/have-worker-thread-update-observablecollection-that-is-bound-to-a.aspx
/// Note: Improved for clarity and the following of proper coding standards.
/// </summary>
/// <param name="e"></param>
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
    // Use BlockReentrancy
    using (BlockReentrancy())
    {
        var eventHandler = CollectionChanged;

        // Only proceed if handler exists.
        if (eventHandler != null)
        {
            Delegate[] delegates = eventHandler.GetInvocationList();

            // Walk thru invocation list
            foreach (NotifyCollectionChangedEventHandler handler in delegates)
            {
                var currentDispatcher = handler.Target as DispatcherObject;

                // If the subscriber is a DispatcherObject and different thread
                if ((currentDispatcher != null) &&
                    (currentDispatcher.CheckAccess() == false))
                {
                    // Invoke handler in the target dispatcher's thread
                    currentDispatcher.Dispatcher.Invoke(
                        DispatcherPriority.DataBind, handler, this, e);
                }

                else
                {
                    handler(this, e);
                }
            }
        }
    }
}

/// <summary>
/// Overridden NotifyCollectionChangedEventHandler event.
/// </summary>
public override event NotifyCollectionChangedEventHandler CollectionChanged;