0

我目前正在开发一个使用 Tasks.Dataflow 的小项目,我对 UI 通知有点困惑。我想在另一个名为 的类中将我的“管道”与 UI 分开PipelineService,但我无法通知 UI 已取消的操作或应显示在 UI 中的数据。如何以正确的方式处理?

代码:

    private void btnStartPipeline_Click(object sender, EventArgs e)
    {
        btnStartPipeline.Enabled = false;
        btnStopPipeline.Enabled = true;

        cancellationToken = new CancellationTokenSource();

        if (head == null)
        {
            head = pipeline.SearchPipeline();        
        }

        head.Post(AppDirectoryNames.STORE_PATH);
    }

    private void btnStopPipeline_Click(object sender, EventArgs e)
    {
        cancellationToken.Cancel();
    } 

此方法与Form1.cs. headITargetBlock<string>.

    public ITargetBlock<string> SearchPipeline()
    { 
        var search = new TransformBlock<string, IEnumerable<FileInfo>>(path =>
            {
                try
                {
                    return Search(path);
                }
                catch (OperationCanceledException)
                {
                    return Enumerable.Empty<FileInfo>();
                }
            });

        var move = new ActionBlock<IEnumerable<FileInfo>>(files =>
            {
                try
                {
                    Move(files);
                }
                catch (OperationCanceledException ex)
                {
                    throw ex;
                }
            });

        var operationCancelled = new ActionBlock<object>(delegate
            {

                form.Invoke(form._update);
            },
            new ExecutionDataflowBlockOptions
            {
                TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
            });

        search.LinkTo(move);

        search.LinkTo(operationCancelled);

        return search;
    }

Invoke不使用委托方法生效。我在这里做错了什么?

4

1 回答 1

1

起初,我不明白你为什么认为你的代码应该工作。您设置数据流网络的方式,块IEnumerable<FileInfo>生成的每个search首先发送到move块。如果move块不接受它(这里从未发生过),它将被发送到operationCancelled块。这似乎根本不是你想要的。

在查看演练之后,您的代码似乎基于,它的取消与您相似,但有一个显着区别:它LinkTo()与谓词一起使用,该谓词拒绝表示取消的消息。如果你想做同样的事情,你还需要使用LinkTo()谓词。而且由于我认为空序列不是表示取消的好选择,我认为您也应该切换到null

此外,form.Invoke()如果您已经在使用TaskScheduler.FromCurrentSynchronizationContext(),则无需使用,它们的作用基本相同。

public ITargetBlock<string> SearchPipeline()
{ 
    var search = new TransformBlock<string, IEnumerable<FileInfo>>(path =>
        {
            try
            {
                return Search(path);
            }
            catch (OperationCanceledException)
            {
                return null;
            }
        });

    var move = new ActionBlock<IEnumerable<FileInfo>>(files =>
        {
            try
            {
                Move(files);
            }
            catch (OperationCanceledException)
            {
                // swallow the exception; we don't want to fault the block
            }
        });

    var operationCancelled = new ActionBlock<object>(_ => form._update(),
        new ExecutionDataflowBlockOptions
        {
            TaskScheduler = TaskScheduler.FromCurrentSynchronizationContext()
        });

    search.LinkTo(move, files => files != null);

    search.LinkTo(operationCancelled);

    return search;
}
于 2012-09-06T00:08:03.553 回答