3

几天来,我一直在试图弄清楚如何做到这一点。

这是一个相当普遍的问题,所以我将尽可能笼统地解释这种情况,以便其他人可以从中获得一些用处。

我的 WPF(使用 MVVM)对话框上有一个列表视图,它绑定到一个可观察的项目集合,例如,五个属性显示在单独的列中。

我调用了一个函数,它遍历所有项目并更改它们的一个属性。此功能需要一段时间才能完成所有项目,因此我希望它随时更新每个项目。

有哪些选项可以做到这一点,以使 UI 保持响应,哪个最容易实现?

4

3 回答 3

4

如果您正在使用C# 4.0,请使用

Task.Factory.StartNew(new Action(() =>
{
    .....
     //CALL YOUR UPDATE METHOD



 })).ContinueWith( { //something to execute after, if need}..)

ModelView当从其他线程设置对象时,使用

Application.Current.Dispatcher.Invoke(new Action(() =>
{
    //set ModelView object properties here
}));
于 2012-10-08T10:54:11.810 回答
2

我会使用一个 ObservableCollection Extender,它允许您在另一个线程中更新集合。这是我在处理集合时在我的应用程序中使用的:

public class ObservableCollectionExtender<T> : ObservableCollection<T>
{
    /// <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;
}
于 2012-10-08T12:49:48.290 回答
0

一种简单的方法,也适用于使用 Netframework 3.5 的人,可以在后台线程上工作并使用同步竞赛进行同步。试试这个:

        var sync = SynchronizationContext.Current;
        BackgroundWorker w = new BackgroundWorker();
        w.DoWork+=(_, __)=>
            {                    
                foreach (var item in collection)
                {
                   //calculate other things
                   sync.Post(p => { ...Actualize UI code... }, null);                  
                }
             }, null);
            };
        w.RunWorkerAsync();
于 2012-10-08T15:03:32.803 回答