如何强制任务在UI线程上运行?

Sha*_*ish 1 c# task windows-8

原始消息如下.让我试着解释为什么我要求这个问题.

我有一个页面,可以收听Share charm请求:

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

当事件触发(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);
}
Run Code Online (Sandbox Code Playgroud)

现在,在GetImage_DelayRender调用时,它也不会在UI线程上调用.但是,在其中,我需要做一堆与UI相关的事情.具体来说,我需要调用一个只能在UI上工作的方法(这是我在别处使用的方法,我想重用它的逻辑).该方法被调用GetImageAsync,它需要在UI上运行,因为它与WriteableBitmap进行了大量的交互.它还会执行一系列异步操作(例如写入流等),这就是为什么它是异步的.我GetImageAsync()尽可能短的时间阻止用户界面.

这是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();
}
Run Code Online (Sandbox Code Playgroud)

我想知道的是,实现上述调用的最正确方法是什么Dispatcher.RunTask()(这是我的hack扩展方法).

-----开始原始信息-------

说我有以下任务:

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

编辑(澄清):我不想阻止UI.我想要执行的任务(即使在示例中,如果您阅读它)也不会阻止UI.我只是希望任务在UI的上下文中运行它的同步部分.

我想在UI线程上的代码上运行此作为Async操作.Dispatcher.RunXXX()方法执行操作,这意味着它们将运行操作并在完成后通知您.这还不够好.我需要在UI线程上运行整个任务(因为如果我从UI线程运行它就会执行),然后,完成后,通知我.

我能想到的唯一方法是使用Dispatcher.RunXXX()方法来执行一个匿名委托,它将我方法中的局部变量设置为任务,然后等待......

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

这看起来非常难看.有没有更好的方法呢?

Edit2:伙计们 - 阅读这段代码 - 如果我使用RunTask()hack执行上面的第一个代码块,它将不会阻塞Task.Delay()上的UI ...

Ste*_*ary 5

我想在UI线程上的代码上运行此作为Async操作.

然后运行它:

async void MyEventHandler(object sender, ...)
{
  await SomeTask();
}
Run Code Online (Sandbox Code Playgroud)

更新:

我不确定这是一个"合法"操作,但您可以通过捕获CoreDispatcherUI处于活动状态并稍后调用时安排该方法在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();
}
Run Code Online (Sandbox Code Playgroud)