0

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

产生新任务时,我需要在我的 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;

                    }
4

2 回答 2

2

您的代码存在一些问题:

  • 您在Thread.SleepUI 线程上使用
  • 您在Task<T>.ResultUI 线程上再次调用 - 在任务完成之前它会阻塞。

你可以做几件事:

  • 用于ProgressBar.IsIndeterminate = true显示选取框样式的进度条,而不是伪造进度更新使用 aDispatcherTimer来更新进度条。
  • 使用任务延续来执行任务完成后需要发生的任何代码。或者,如果您使用的是 .NET 4.5,则可以使用该语言的新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);
    }
}

要使用延续:

Task.Factory.StartNew(() => queryHandler.GetItemssStatistics(...))
    .ContinueWith(task => ProcessResults(task.Result), TaskScheduler.FromCurrentSynchronizationContext());

FromCurrentSynchronizationContext方法创建一个任务调度程序,用于SynchronizationContext将调用编组回 UI 线程。

显然使用 await/async 更容易,如果可用,应该是您的首选。

于 2013-03-11T11:56:09.790 回答
0

您仍在阻止 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);
}

代表的签名可能是这样的:

公共无效 MyDelegate();

于 2013-03-11T11:34:19.210 回答