使用返回值在单独的线程上运行任务

本文关键字:线程 运行 任务 单独 返回值 | 更新日期: 2023-09-27 18:03:14

我正在开发一个应用程序,它应该运行一个新任务,制作一些东西并返回一个对象列表…

当生成新任务时,我需要在我的UI线程中模拟一个for循环中变化的进度条…任务完成后,我必须更新我的视图(通过更新我的ViewModel属性的值,因为我使用MVVM模式)。

的问题是,当任务启动时,GUI冻结,进度条没有更新!我认为任务是在后台运行在一个单独的线程(因为它们是池)。为什么我的GUI被屏蔽了?

下面是我的代码片段:

Task<List<Items>> myTask = Task.Factory.StartNew(() => queryHandler.GetItemssStatistics(items, sec, buyer, seller, From, To));
//Here is the simulation of ProgressBar changing that i need to be done when task is started
                    for (int i = 0; i < 100; i++)
                    {
Thread.Sleep(100);
                        StatusValue = i+1;
                    }
//Here is the section i need to do once the task finishes its execution to update my VM
//Wait for the task to finish its execution and retreive results:
                    List<Items> _tempResults = myTask.Result;
                    foreach (Items d in _tempResults)
                    {
                        ResultsList.Add(d);
                    }
                    if (ResultsList.Count == 0)
                    {
                        MessageBox.Show("Sorry, No items matched the defined research criteria!", "Warning",
                                        MessageBoxButton.OK,
                                        MessageBoxImage.Warning, MessageBoxResult.OK, MessageBoxOptions.ServiceNotification);
                    }
                    else
                    {
                        //Show items:
                        ResultsAvailable = Visibility.Visible;
                    }

使用返回值在单独的线程上运行任务

你的代码有几个问题:

  • 你正在UI线程上使用Thread.Sleep
  • 你在UI线程上再次调用Task<T>.Result -它阻塞直到任务完成。

你可以做几件事:

  • 使用ProgressBar.IsIndeterminate = true来显示一个选框样式的进度条而不是伪造进度更新使用DispatcherTimer来更新进度条

  • 使用async/await:

     async Task GetItems()
     {
         List<Items> tempResults = await Task.Run(() => queryHandler.GetItemssStatistics(...));
         // the following will be executed on the UI thread automatically
         // after the task is done, keeping the UI responsive
         foreach (Items d in _tempResults)
         {
             ResultsList.Add(d);
         }
     }
    

您仍然在阻止UI工作,因为您正在调用Thread.Sleep。如果你想要你的进度条更新,运行另一个线程,或者尝试在你的任务中集成进度条的增加。看看你的代码,最好在你的任务中更新进度条!
您正在让用户等待10000毫秒,如果您的任务在此之前完成,用户必须等待…
当一个项目已经进行时,访问任务中进度条的调度程序,并执行

//process item
if(progressBar.Dispatcher.CheckAccess()){
progressBar.Value += 1; //maybe calculate the number of items you are processing
}
else {
//send a delegate to the dispatcher
MyDelegate myDel = new MyDelegate(delegate() {
   progressBar.Value += 1;
});    
progressBar.Dispatcher.Invoke(myDel);
}

委托的签名可以是这样的: