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ます。headのタイプですITargetBlock<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ます。それはあなたが望んでいるものではないようです。

コードのベースになっているように見える walkthrough を見た後、それはあなたと同様のキャンセルを行いますが、1 つの重要な違いが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 に答える