3

UI がブロックされている問題を解決しようとしていますが、その理由がわかりません。

public Task AddStuff(string myID, List<string> otherIDs)
{
    Action doIt = () =>
    {
        this.theService.AddStuff(myID, otherIDs);
    };

    return Task.Factory.StartNew(doIt, TaskCreationOptions.LongRunning);
}

リストが長い場合、呼び出しに 30 秒かかる場合があり、アプリケーション全体が応答しなくなります (Windows 7 では白くなります)。

UIをブロックしないようにこれを行う別の方法はありますか?


編集

わかりました、これにはたくさんのコードがあります。これを適切に保つようにします。元のコードに戻ると、重要だったかもしれない何かを削除したことに気付きました。とは異なる TaskScheduler を使用する必要がありTaskScheduler.Currentますか?

また、このコードを妨げる Wait ステートメントはなく、サービスは UI と対話しません。

Task.Factory.StartNew(objState =>
    {
        LoadAssets(objState);
    }, state, this.cancellationToken, TaskCreationOptions.LongRunning, TaskScheduler.Current);

private void LoadAssets(object objState)
{
    LoadAssetsState laState = (LoadAssetsState)objState;

    List<string> assetIDs = new List<string>();

    for (int i = 0; i < laState.AddedMediaItems.Count; i++)
    {
        if (laState.CancellationToken.IsCancellationRequested)
            return;

        string assetId = this.SelectFilesStep.AssetService.GetAssetId(laState.AddedMediaItems[i], laState.ActiveOrder.OrderID);

        assetIDs.Add(assetId);

    }

    if (laState.CancellationToken.IsCancellationRequested)
        return;

    this.ApiContext.AddAssetToProduct(laState.ActiveOrder.OrderID, laState.ActiveProduct.LineID, assetIDs, laState.Quantity, laState.CancellationToken).ContinueWith(task =>
    {
        if (laState.CancellationToken.IsCancellationRequested)
            return;


        App.ApiContext.GetOrderDetails(laState.ActiveOrder.OrderID, false, laState.CancellationToken).ContinueWith(orderDetailsTask =>
        {
            if (laState.CancellationToken.IsCancellationRequested)
                return;

            this.activeOrder = orderDetailsTask.Result;

            this.StandardPrintProductsStep.Synchronize(this.activeOrder);

        });
    });
}

public Task AddAssetToProduct(string orderID, string lineID, List<string> assetIDs, int quantity, CancellationToken? cancellationToken = null)
{
    Action doIt = () =>
    {
        if (cancellationToken.IsCancellationRequested())
            return;

        this.ordersService.AddAssetToProduct(orderID, lineID, assetIDs, quantity);
    };

    if (cancellationToken != null)
        return Task.Factory.StartNew(doIt, cancellationToken.Value, TaskCreationOptions.LongRunning, TaskScheduler.Current);
    else
        return Task.Factory.StartNew(doIt, TaskCreationOptions.LongRunning);
}

編集

サービス コールの直前と直後にブレーク ポイントを配置しました。他の行とは対照的に、UI をブロックしているのはサービス コールです。

これがブロックされる理由はないように思われるので、リストが長い場合は分割して複数の呼び出しを行うだけだと思います。タスク ロジックでここに何かが欠けていないことを確認したかっただけです。

4

2 に答える 2

6

UIをブロックしないようにこれを行う別の方法はありますか?

この呼び出し自体は、UI をブロックするべきではありません。ただし、theService.AddStuffUI の SynchronizationContext と何らかの同期を行うと、その呼び出しによって UI が効果的にブロックされる可能性があります。

それ以外の場合、問題はこの関数の外部で発生している可能性があります。たとえば、Wait()このメソッドから返されたタスクを UI スレッドで呼び出すと、UI スレッドはこれが完了するまでブロックされます。


おそらくTaskScheduler.Defaultではなく、 TaskScheduler.Default を使用する必要がありTaskScheduler.Currentます。これが、UI スレッドに基づいて TaskScheduler でスケジュールされた Task 内で呼び出されている場合、UI スレッドでスケジュールされます。

于 2012-06-05T21:53:14.910 に答える
0

フォーマットされたコードをコメントに入れたいのですが、方法がわからないので、このスニペットを回答として追加してください。これは、タスクが UI スレッドで実行されているかどうかを判断し (実行したくないため)、アクションをまったく異なるもの (単純な thread.sleep) にするために使用する一種のアプローチです。

var state = new object();
var cancellationTokenSource = new CancellationTokenSource();
var cancellationToken = cancellationTokenSource.Token;

var task = Task.Factory.StartNew(
    objState => { Console.WriteLine ("Current thread is {0}", Thread.CurrentThread.ManagedThreadId); Thread.Sleep(30); },
    state,
    cancellationToken,
    TaskCreationOptions.LongRunning,
    TaskScheduler.Current);

task.Wait();    
于 2012-06-06T13:42:32.267 に答える