可以使用任务并行库一起运行长时间运行的方法和“工作…”对话框,以允许长任务写入BindingList吗?

我有一个WPF(C#和.NET 4)应用程序,其中有一个长时间运行的任务阻止了UI,给人的印象是它已挂起。 我决定使用BackgroundWorker线程将这个长时间运行的任务放到一个单独的线程中,并在一个单独的弹出窗口中显示一个BusyIndicator (下面名为WorkingDialog)。 这很好用,直到长时间运行的任务写入BindingList(绑定到UI上的网格),我得到以下exception:

这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection

这是(业务层代码的一个非常精简的版本)…

 public class CustomMessage { public DateTime TimeStamp { get; private set; } public string Message { get; private set; } public CustomMessage(string message) { Message = message; TimeStamp = DateTime.Now; } } public class MyRandomBusinessClass { public BindingList LoggingList { get; private set; } public MyRandomBusinessClass() { LoggingList = new BindingList(); } public void SomeLongRunningTask() { System.Threading.Thread.Sleep(5000); LoggingList.Add(new CustomMessage("Completed long task!")); } } 

… UI …

    

…… UI代码……

 using System.ComponentModel; using System.Windows; namespace WpfApplication4 { ///  /// Interaction logic for MainWindow.xaml ///  public partial class MainWindow : Window { public MyRandomBusinessClass RandomBusinessClass { get; set; } public MainWindow() { InitializeComponent(); RandomBusinessClass = new MyRandomBusinessClass(); logGrid.DataContext = RandomBusinessClass; } private void ProcessLongTask_Click(object sender, RoutedEventArgs e) { ProcessTask1(); } private void ProcessTask1() { WorkingDialog workingDialog = new WorkingDialog(); workingDialog.Owner = this; BackgroundWorker worker = new BackgroundWorker(); worker.DoWork += delegate(object s, DoWorkEventArgs args) { RandomBusinessClass.SomeLongRunningTask(); }; worker.RunWorkerCompleted += delegate(object s, RunWorkerCompletedEventArgs args) { workingDialog.Close(); }; worker.RunWorkerAsync(); workingDialog.ShowDialog(); } } } 

……工人对话……

      

我在这个论坛中找到了几个指向Bea Stollnitz工作的线程,但我想知道是否有办法执行长时间运行的任务,显示WorkingDialog,然后在任务完成后关闭对话框使用任务并行库? 任务并行库是否可以实现所需的结果而无需修改业务层代码?

编辑 – 解决方法1

感谢Ben下面的评论,如果长时间运行的任务与UI在同一个程序集中或使用System.Windows命名空间,则有一种解决方法。 使用当前的应用程序调度程序,我可以将消息添加到我的列表,没有例外:

 public class MyRandomBusinessClass { public BindingList LoggingList { get; private set; } public MyRandomBusinessClass() { LoggingList = new BindingList(); } public void SomeLongRunningTask() { System.Threading.Thread.Sleep(5000); Dispatcher myDispatcher = Application.Current.Dispatcher; myDispatcher.BeginInvoke((Action)(() => LoggingList.Add(new CustomMessage("Completed long task!")))); } } 

我仍然很好奇这是否可以使用任务并行库或我咆哮错误的树?! 在我的实际应用程序中,长时间运行的类位于单独的类库中。

编辑2

我接受了下面的Ben的解决方案,因为它解决了我的初始问题,即在不阻止UI或抛出exception的情况下运行长时间运行的任务。 我很欣赏最初的问题是关于任务并行库,所以如果你正在阅读这个认为它有TPL解决方案的话,请原谅我。

您需要使用调度程序将新元素添加到日志列表中。

 public void SomeLongRunningTask() { System.Threading.Thread.Sleep(5000); Application.Current.Dispatcher.BeginInvoke((Action)(() => LoggingList.Add(new CustomMessage("Completed long task!")))); } 

编辑

 public class MyRandomBusinessClass { public BindingList LoggingList { get; private set; } public Action CallBackAction { get; private set; } public MyRandomBusinessClass(Action cba) { LoggingList = new BindingList(); this.CallBackAction = cba; } public void SomeLongRunningTask() { System.Threading.Thread.Sleep(5000); if (cba != null) CallBackAction(this, new CustomMessage("Completed long task!")); } } 

然后,您在哪里创建您的业务类:

 MyRandomBusinessClass businessClass = new MyRandomBusinessClass((sender, msg) => Application.Current.Dispatcher.BeginInvoke((Action)(() => sender.LoggingList.Add(msg))));