WPF MVVM和TPL数据流中的进度条

SOf*_*tic 5 c# wpf mvvm task-parallel-library tpl-dataflow

我在遵循MVVM模式的WPF应用程序中使用TPL数据流.我有一个TransformBlock<object,object>ActionBlock<object>我一样,我将它们连接起来:

transformBlock.LinkTo(notificationBlock);
Run Code Online (Sandbox Code Playgroud)

ActionBlock<object>应更新我对当前进度视图的进度条,但UI似乎被冻结,只有当一切都完成处理更新.

我的CurrentProgress财产看起来像这样:

private double _CurrentProgress;

public double CurrentProgress
{
    get { return _CurrentProgress; }
    set
    {
        _CurrentProgress = value;
        RaisePropertyChanged("CurrentProgress");
    }
}
Run Code Online (Sandbox Code Playgroud)

并且我将它绑定到我的View,就像这样:

<ProgressBar Value="{Binding CurrentProgress, Mode=OneWay}" Name="uxProgressBar"/>
Run Code Online (Sandbox Code Playgroud)

我错过了什么吗?为什么TPL会阻止UI线程?

编辑

这就是我实例化TPL的方式:

foreach(var myObj in ObjList)
{
    transformBlock.Post(myObj);
}
Run Code Online (Sandbox Code Playgroud)

变换块:

TransformBlock<object, object>(
temp =>
{
    var response = ProcessRecord(temp);
    return response.Status;
},
new ExecutionDataflowBlockOptions
{
    MaxDegreeOfParallelism =20
});
Run Code Online (Sandbox Code Playgroud)

行动阻止:

ActionBlock<object>(
temp =>
{
    CurrentProgress = (double)temp.RecordNumber/(double)TotalRecords;
},
new ExecutionDataflowBlockOptions
{
    TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
});
Run Code Online (Sandbox Code Playgroud)

UPDATE

正在调用的Web服务是TransformBlock遗留(asmx)Web服务,并且未被调用Async.解决此问题后,其他一切工作正常,而不使用Dispatcher或任何其他建议的解决方案.

从其中一个评论到问题,似乎WPF确实支持从另一个线程发布到UI线程.我找不到任何关于此的官方文档.

Ger*_*ace 2

首先,您ActionBlock不必CurrentProgress直接更改属性。

原因是该RaisePropertyChanged函数将直接运行ProgressBar对象的代码。这是不允许的,因为它是 UIThread 拥有的对象。

在他自己的线程中运行ActionBlock,他需要将进度条更新顺序发布到 UI 线程(通过使用)Dispatcher.BeginInvoke

ActionBlock<object>(
temp =>
{
    double progress = (double)temp.RecordNumber/(double)TotalRecords;
    Dispatcher.BeginInvoke((Action)(() =>
    {
        CurrentProgress = progress;
    }));
},
new ExecutionDataflowBlockOptions
{
    TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
});
Run Code Online (Sandbox Code Playgroud)

为了做出你想要的东西,你必须首先改变这一点。

其次(如果这不会改变任何事情),您必须检查您的 UI 线程是否正在等待TransformBlock. 如果您的ICommand(例如,如果您从按钮调用它)不是异步的,请执行以下操作:

transformBlock.Completion.Wait();
Run Code Online (Sandbox Code Playgroud)

不行。因为你的UIThread会等待你的处理结束并且不会接受之前的progressBar更新命令直到结束。

祝你好运 !如果它始终不起作用,请发布新的详细信息。