【问题标题】:Using MVVM on a View that has a long running process在具有长时间运行进程的视图上使用 MVVM
【发布时间】:2012-05-22 09:33:47
【问题描述】:

我在这里有一个示例,可以复制我想要完成的任务。 正如以下代码所示 - 我有 ViewModel 更新绑定到视图的 ObservableCollection 属性。通常我会根据从模型中检索到的结果来更新集合,但希望这个示例就足够了。

using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Controls;

namespace MVVMWpf.ViewModel
{
    public class ListViewModel
    {

        public ObservableCollection<int> SomeObjectCollection { get; set; }

        public ListViewModel()
        {

            SomeObjectCollection = new ObservableCollection<int>();

        }

        public void Do()
        {
             for (int i = 1; i < 1000000; i++)
             {
                 int i1 = i;
                 SomeObjectCollection.Add(i1);
             }
        }

    }
}

很遗憾,这会阻止此 UI。它只会在循环运行完成时更新视图。我解决它的方式打破了 MVVM 概念。这就是为什么我需要你的帮助。我是这样做的。

public class ListViewModel
{
    private delegate void LongRunningProcess();
    public ObservableCollection<int> SomeObjectCollection { get; set; }
    private ListBox listBox;
    public ListViewModel(ListBox listBox)
    {
        this.listBox = listBox;
        SomeObjectCollection = new ObservableCollection<int>();

    }

    public void Do()
    {
        Thread thread = new Thread(() =>
        {
           for (int i = 1; i < int.MaxValue; i++)
           {
               int i1 = i;
               listBox.Dispatcher.Invoke(
                   new LongRunningProcess(() =>
                   SomeObjectCollection.Add(i1);
                 }});

        thread.SetApartmentState(ApartmentState.STA);
        thread.Start();
    }

}

如您所见,ViewModel 现在知道 UI 中的 listBox 元素。并且查看 MVVM 图,只有 View 应该通过绑定来引用 ViewModel。如何克服这个问题? 谢谢。

【问题讨论】:

  • 如何克服什么问题?

标签: c# wpf silverlight mvvm


【解决方案1】:

您需要让您的循环释放屏幕更新 - 某种 DoEvents() 可以:

public static void DoEvents() 
{ 
    Application.Current.Dispatcher.Invoke(
    DispatcherPriority.Background,new Action(delegate { })); 
}

添加它并在你的循环中调用它。


使用计时器作为另一个选项,您的代码应该看起来像这样:

private System.Timers.Timer operationsTimer = new System.Timers.Timer();
private int x;

在你的 ctor 中:

operationsTimer.Elapsed += new System.Timers.ElapsedEventHandler 
(operationsTimer_Elapsed);
operationsTimer.Enabled = true;

在你的计时器中:

operationsTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{ 
    operationsTimer.Enabled = false;
    //add item to collection code
    x++;
    if(x<100)
        operationsTimer.Enabled = true;
}

【讨论】:

  • 哈哈好笑,我实际上是在发布问题后发现的。但是当我关闭程序时它会引发异常......
  • 另一种选择是使用计时器而不是线程内循环。
  • 如果我能处理该异常,我听起来像是我想要的解决方案。有没有办法在应用程序关闭时退出所有线程。也许我应该听 window.close 事件
  • 在这种情况下我将如何使用计时器。我想尝试将其作为另一种选择。谢谢
  • 我会在答案中添加计时器选项。
【解决方案2】:

考虑使用BackgroundWorker,这是一种执行异步任务的简单方法,具有报告进度和已完成事件的功能。最重要的是,您不必在调度程序上调用任何东西,因为 BackgroundWorker 的函数与 UI 线程同步。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多