WPF Dispatcher不像BGWorker那样工作

时间:2011-12-22 07:49:42

标签: wpf multithreading mvvm backgroundworker dispatcher

我在MVVM应用程序中。这里我有一个集合(ObservableCollection),它可以添加,删除从不同线程完成的操作。 这是代码。我试图让它尽可能完整:

private Thread _thread = null;
private Dispatcher _UIDispatcher = null;
public ObservableCollection<string> ListOfStrings { get; private set; }

ctor:

 public MainWindowViewModel(Dispatcher dispatcher)
 {
            this.ListOfStrings = new ObservableCollection<string>();
            this.StartAsyncCall = new RelayCommand(AsyncCall, CanCallAsynch);
            this._UIDispatcher = dispatcher;
 }

我将View的调度程序作为参考(虽然这不是一个好的做法,因为它使单元测试变得困难.Gary Hall提出了一个使用AOP的好方法。我可以随时改变它。)。然后我通过命令

调用此方法
private void AsyncCall()
{
    if (this.ListOfStrings.Count > 0)
       this.ListOfStrings.Clear();
     //_backgroundWorker.RunWorkerAsync();
    this._thread = new Thread(new ThreadStart(AddNumbersToList));
    this._thread.IsBackground = true;
    this._thread.Start();
}
 private void AddNumbersToList()
 {
       Action delAddNum = new Action(AddNumbersToList);
       for (int i = 0; i < 100000000; i++)
       {
           if (null != this._UIDispatcher &&
            !this._UIDispatcher.CheckAccess())
                    _UIDispatcher.Invoke(DispatcherPriority.Render,delAddNum);
           else
           {
                    this.ListOfStrings.Add(Convert.ToString(i.ToString()));
           }
        }
  }

ObservableCollection绑定到View中的列表框。

我预期的效果是,当ObservableCollection添加了新的数字时,它们应该显示在UI中。用户界面也会很敏感。但奇怪的是,用户界面没有反应。当我试图通过后台工作者实现时,同样的事情已经很好地实现了。有人可以指出我哪里错了。我不想去后台工作者,因为我想要使用更细粒度的Thread类的灵活性。 以下是我与BGWorker一起使用的代码,运行正常:

    private BackgroundWorker _backgroundWorker = new BackgroundWorker();

CTOR:

public MainWindowViewModel()
{
     this.ListOfStrings = new ObservableCollection<string>();
     this.StartAsyncCall = new RelayCommand(AsyncCall, CanCallAsynch);
     _backgroundWorker.DoWork += AddNumbersToList;
     _backgroundWorker.RunWorkerCompleted += this.LoadResultsCompleted;
     _backgroundWorker.WorkerReportsProgress = true;
     _backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(_backgroundWorker_ProgressChanged);
}

方法:

 private void AsyncCall()
 {
    if (this.ListOfStrings.Count > 0)
      this.ListOfStrings.Clear();
      this._backgroundWorker.RunWorkerAsync();
 }

private void AddNumbersToList(object sender, DoWorkEventArgs e)
{
      BackgroundWorker bw = sender as BackgroundWorker;
      if(null!=bw)
      for (int i = 0; i < 10; i++)
      {
           bw.ReportProgress(0, i);
                    Thread.Sleep(1000);
        }
 }


 private void LoadResultsCompleted(object sender, RunWorkerCompletedEventArgs e)
 {
   if (e.Error == null)
   {
            this.ListOfStrings.Add("Completed");
            CommandManager.InvalidateRequerySuggested();
   }
 }

//This works just wonderful:
void _backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
    this.ListOfStrings.Add(Convert.ToString(e.UserState.ToString()));
}

提前谢谢。

..詹姆斯

1 个答案:

答案 0 :(得分:0)

它挂起代码的递归......

这对我有用......

    private void AsyncCall()
    {
        if (this.MyCollection.Count > 0)
            this.MyCollection.Clear();

        this._thread = new Thread(new ThreadStart(AddNumbersToList));
        this._thread.IsBackground = true;

        this._thread.Start();
    }

    private void AddNumbersToList()
    {
        for (int i = 0; i < 100000000; i++)
        {
            this.Dispatcher.Invoke(
                new Action(
                    delegate
                        {
                            this.MyCollection.Add(Convert.ToString(i.ToString()));
                        }));

            Thread.Sleep(100);
        }
    }