1

以下元のメッセージ。なぜ私がこれを求めているのか、より詳細に説明してみましょう。

共有チャーム リクエストをリッスンするページがあります。

void Page_Loaded(object sender, RoutedEventArgs e)
{
    m_transferManager = Windows.ApplicationModel.DataTransfer.DataTransferManager.GetForCurrentView();
    m_transferManager.DataRequested += TransferManager_DataRequested;
}

イベントが発生しても ( TransferManager_DataRequested)、UI スレッドでは発生しません。

void TransferManager_DataRequested(DataTransferManager sender, DataRequestedEventArgs args)
{
    var data = args.Request.Data;
          // More related stuff omitted - not important.
    data.SetDataProvider(StandardDataFormats.Bitmap, GetImage_DelayRenderer);
}

これで、GetImage_DelayRenderが呼び出されたときに、UI スレッドでも呼び出されなくなりました。ただし、その中で、UI 関連の処理を行う必要があります。具体的には、UI でのみ機能するメソッドを呼び出す必要があります (これは別の場所で使用するメソッドであり、そのロジックを再利用したい)。メソッドが呼び出さGetImageAsyncれ、UI で実行する必要があります。これは、WriteableBitmap との一連の対話を行うためです。また、一連の非同期操作 (ストリームへの書き込みなど) も実行するため、非同期です。GetImageAsync()できるだけ短い時間だけUI をブロックします。

GetImage_DelayRender外観は次のとおりです。

private async void GetImage_DelayRenderer(DataProviderRequest request)
{
    var deferral = request.GetDeferral();
    await Dispatcher.RunTask(async () => // RunTask() is an extension method - described in the original question below.
        {
            try
            {
                var bitmapStream = await GetImageAsync();
                request.SetData(RandomAccessStreamReference.CreateFromStream(bitmapStream));
            }
            catch
            {
            }
        });

    deferral.Complete();
}

私が知りたいのは、Dispatcher.RunTask()上記の呼び出しを実現する最も正しい方法は何ですか (これは私のハック拡張メソッドです)。

----- オリジナルメッセージの開始 -------

次のタスクがあるとします。

private async Task SomeTask()
{
   await Task.Delay(1000);
   // Do some UI and other stuff that may also be async
}

編集 (明確化): UI をブロックしたくありません。私が実行したいタスクは(例を読んでも)UIをブロックしません。同期部分の UI のコンテキストでタスクを実行したいだけです。

これを UI スレッドのコードで非同期操作として実行したいと考えています。Dispatcher.RunXXX() メソッドはアクションを実行します。つまり、アクションを実行し、完了したら通知します。それは十分ではありません。タスク全体を UI スレッドで実行する必要があり (UI スレッドから実行した場合は実行されたはずです)、完了したら通知を受け取る必要があります。

私が考えることができる唯一の方法は、Dispatcher.RunXXX() メソッドを使用して、メソッド内のローカル変数をタスクに設定し、それを待機する anon デリゲートを実行することです...

public async static Task RunTask(this CoreDispatcher dispatcher, Func<Task> taskGiver)
{
    Task task = null;
    await dispatcher.RunAsync(() => task = taskGiver());
    await task;
}

これはかなり醜いように見えます。それを行うより良い方法はありますか?

Edit2:みんな-このコードを読んでください-私が持っているRunTask()ハックを使用して上記の最初のコードブロックを実行すると、Task.Delay()のUIをブロックしません...

4

3 に答える 3

5

これをUIスレッドのコードで非同期操作として実行したいと思います。

次に、それを実行します。

async void MyEventHandler(object sender, ...)
{
  await SomeTask();
}

アップデート:

これが「合法的な」操作であるかどうかはわかりませんがCoreDispatcher、UIがアクティブである間にキャプチャし、後で呼び出すことで、UIスレッドで実行するようにそのメソッドをスケジュールできRunAsyncます。

private async void GetImage_DelayRenderer(DataProviderRequest request)
{
  var deferral = request.GetDeferral();
  Task task = null;
  await coreDispatcher.RunAsync(() => { task = SomeTask(); });
  await task;
  deferral.Complete();
}
于 2013-01-08T13:40:30.367 に答える
1

完全な解決策を実行する時間がないため、これが役立つことを願っています...

まず、他の人が指摘しているように、UI スレッドで何かを実行することはできず、UI スレッドをブロックすることはできません。議論の終わり。あなたが必要としているのは、非 UI スレッドで実行し、処理が必要な更新があることを定期的に UI スレッドに通知するものです。

これを実現するには、次のようなものが必要です...

public class LongTask
    {
        public event EventHandler MyEvent;

        public void Execute()
        {
            var task = Task.Factory.StartNew(() =>
            {

                while (true)
                {
                    // condition met to notify UI
                    if (MyEvent != null)
                        MyEvent(this, null);
                }
            });
        }
    }

あなたのUIで、次のようなことをしてください...

private void button_Click(object sender, RoutedEventArgs e)
        {
            var test = new LongTask();
            test.MyEvent += test_MyEvent;
            test.Execute();
        }

        void test_MyEvent(object sender, EventArgs e)
        {
            Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                test.Text += " bang ";
            });

明らかに、MVVM のようなものを使用して、よりクリーンな方法でこれを実装できますが、これが基本的な考え方です。}

于 2013-01-08T14:51:49.850 に答える
0

私はこのようにしました:

public static Task<string> GetResultAsync()
{
    return Task<string>.Factory.StartNew(() => GetResultSync());
}

UI で:

private async void test()
{

    string result = await GetResultAsync();

    // update UI no problem  
    textbox.Text = result;  

}
于 2013-01-08T13:37:32.697 に答える