WPF 调度程序不像 BGWorker 那样工作

发布于 2024-12-22 16:37:48 字数 3183 浏览 0 评论 0原文

我正在开发 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;
 }

我将视图的调度程序作为参考(尽管这不是一个好的做法,因为它使单元测试变得困难。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 调用的这个方法被绑定到视图中的列表框。

我期望的效果是,当 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()));
}

提前谢谢您。

..詹姆斯

I am in mid of an MVVM application. Here I have a collection (ObservableCollection) that may have add, delete operations done from a different thread.
Here is the code. I have tried to keep it as complete as possible:

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

The ctor:

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

I am taking the View's dispatcher as a reference (It is not a good practice though as it makes Unit testing difficult. Gary Hall suggested a nice approach using AOP. I can change that later anytime though.). And then this method that I call via a command

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

The ObservableCollection is bound to a listbox in the View.

The effect that I expected was, as the ObservableCollection gets new numbers added, They should be displayed in the UI. The UI would be nicley responsive too. But strangely the UI is unresponsive. The same thing when I am trying to achieve via a background worker is finely achieved. Can someone please point where am I going wrong. I don't want to go for the background worker as I want the flexibility of using the more granular Thread class.
Below is the code that I am using with BGWorker and it is running fine:

    private BackgroundWorker _backgroundWorker = new BackgroundWorker();

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

The methods:

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

Thank you in advance.

..James

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

故人如初 2024-12-29 16:37:48

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

这对我有用......

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

Its the recursion that is hanging your code...

This works for me...

    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);
        }
    }
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文