C# WPF MVVM和TPL数据流中的进度条
我在遵循MVVM模式的WPF应用程序中使用TPL数据流。 我有一个C# WPF MVVM和TPL数据流中的进度条,c#,wpf,mvvm,task-parallel-library,tpl-dataflow,C#,Wpf,Mvvm,Task Parallel Library,Tpl Dataflow,我在遵循MVVM模式的WPF应用程序中使用TPL数据流。 我有一个TransformBlock和一个ActionBlock,我这样链接它们: transformBlock.LinkTo(notificationBlock); ActionBlock应该用当前进度更新我视图中的进度条,但UI似乎已冻结,只有在所有操作完成后才会更新 我的CurrentProgress属性如下所示: private double _CurrentProgress; public double CurrentPro
TransformBlock
和一个ActionBlock
,我这样链接它们:
transformBlock.LinkTo(notificationBlock);
ActionBlock
应该用当前进度更新我视图中的进度条,但UI似乎已冻结,只有在所有操作完成后才会更新
我的CurrentProgress
属性如下所示:
private double _CurrentProgress;
public double CurrentProgress
{
get { return _CurrentProgress; }
set
{
_CurrentProgress = value;
RaisePropertyChanged("CurrentProgress");
}
}
我把它和我的观点联系在一起,就像这样:
<ProgressBar Value="{Binding CurrentProgress, Mode=OneWay}" Name="uxProgressBar"/>
变换块:
TransformBlock<object, object>(
temp =>
{
var response = ProcessRecord(temp);
return response.Status;
},
new ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism =20
});
TransformBlock(
温度=>
{
var响应=过程记录(温度);
返回响应状态;
},
新的ExecutionDataflowBlockOptions
{
MaxDegreeOfParallelism=20
});
动作块:
ActionBlock<object>(
temp =>
{
CurrentProgress = (double)temp.RecordNumber/(double)TotalRecords;
},
new ExecutionDataflowBlockOptions
{
TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
});
ActionBlock(
温度=>
{
CurrentProgress=(双)临时记录编号/(双)总计记录;
},
新的ExecutionDataflowBlockOptions
{
TaskScheduler=TaskScheduler.FromCurrentSynchronizationContext()
});
更新
TransformBlock
中调用的web服务是一个遗留(asmx)web服务,它没有被称为Async
。解决此问题后,其他一切都可以正常工作,无需使用调度程序
或任何其他建议的解决方案
从一条评论到问题,WPF似乎确实支持从另一个线程发布到UI线程。我还没有找到任何关于此的官方文档。尝试使用“SendAsync”将代码发布到TransformBlock:
foreach (var myObj in ObjList)
{
await transformBlock.SendAsync(myObj);
}
您应该使用
Dispatcher
通知UI线程您要从后台进程更新绑定值
以下是一篇文章的链接,该文章解释:
我将整理一个类似的代码示例,并很快更新此响应。首先,您的
ActionBlock
不必直接更改CurrentProgress
属性
原因是RaisePropertyChanged
函数将直接运行ProgressBar
对象的代码。
这是不允许的,因为它是UIThread拥有的对象
ActionBlock
在他自己的线程中运行,他需要将progressBar更新顺序发布到UI线程(通过使用Dispatcher.BeginInvoke
):
不好。因为您的UIThread将等待治疗结束,并且在治疗结束之前不会接受以前的progressBar更新命令
祝你好运!
如果它总是不起作用,请发布新的详细信息。您如何实例化
TPL?
发布相关代码,您可能没有正确地“等待”您的代码。我喜欢在示例项目中工作。我没有第三方物流的例子,但看看这个项目。让TPL在这个示例项目中工作,然后转到您的生产项目。您是否正在等待块的完成
,或者类似的事情?有多少项以及处理它们需要多长时间?@svick我对第三方物流数据流相当陌生。我发布的代码基本上是所有代码,在其他任何地方都没有Wait()
。从后台线程访问CurrentProgress不会引发InvalidOperationException吗?他应该看到这一点,或者ActionBlock正在吞噬异常?正如您所说,它被吞噬了。只有在调试应用程序时(选中Debug->Exception->catch exceptions),或者在等待ActionBlock.Completion时,才能看到它。Wait()。抛出的异常将对您的TPL网络产生影响(至少它会杀死您的ActionBlock线程),但不会直接通知您的主线程(在本例中为UIThread),除非您在他和您的TPL线程之间创建依赖关系(例如,通过等待其中一个线程)。如果您对这个特定主题感兴趣,您可能会在这里找到一些有用的信息:我知道TPL传播异常的方式,我想知道数据流的行为是否相同:)我刚刚在没有try/catch块的情况下运行了其中一个,并且确认,主线程没有意识到异常。在ActionBlock端,.Completion.IsFaulted
变为true,不再处理输入。这就是全部。
foreach (var myObj in ObjList)
{
await transformBlock.SendAsync(myObj);
}
ActionBlock<object>(
temp =>
{
double progress = (double)temp.RecordNumber/(double)TotalRecords;
Dispatcher.BeginInvoke((Action)(() =>
{
CurrentProgress = progress;
}));
},
new ExecutionDataflowBlockOptions
{
TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
});
transformBlock.Completion.Wait();