如何在线程安全方法中调用Dispatcher.RunAsync()来更新UI组件

时间:2017-10-23 01:10:08

标签: c# multithreading uwp

首先,经过深思熟虑,我认为我没有正确地提出这个标题。

但是,我一直在尝试从Task.Run(async()=> {})表达式/方法中生成的多个线程中找到更新UI控件的方法。我在UWP windows mobile 10应用程序中这样做。

我已经列出了大部分涉及的例程,并且需要帮助完成对DisplayProgress(字符串消息)方法的调用。在这个方法中,我想使用Dispathcer.RunAsync()以线程安全的方式更新UI控件,但需要它是线程安全的。请参阅以下代码中的尝试1& 2

void printMessage(int value) {
    System.out.println("Your score is " + score);
}

我发现了这篇文章http://briandunnington.github.io/uitask.html,但是,我不确定这种方法是正确的还是线程安全的。对于应该由Dispatacher.RunAsync()处理的东西,似乎有很多样板代码?我读过的其他文章指向Action代理,我认为它应该是线程安全的,但经过几次(非常详细的技术文章)之后,我现在感到困惑。其他文章:Are C# delegates thread-safe?(不幸的是,我只能链接到2篇文章 - 需要先提高我的积分!)

2 个答案:

答案 0 :(得分:3)

  

我不确定这种方法是正确的还是线程安全的。看起来像Dispatacher.RunAsync()应该处理的很多样板代码?

You can access the UI element safely使用其Dispatcher属性,或者UI线程上下文中存在的任何对象的Dispatcher属性(,例如按钮所在的页面)。

在UI线程上创建的Windows运行时对象的生命周期受线程生命周期的限制。窗口关闭后,不要尝试访问UI线程上的对象。

以下是对Microsoft github repository的正式建议。

  

通常,您可以通过调用Dispatcher.RunAsync(CoreDispatcherPriority.Normal,()=> / *更新UI * /)从后台线程更新UI。但是,这仅仅调度UI线程上的工作并立即返回,即使任务是等待弹出框中的用户输入。它也没有为任务提供将结果返回给调用者的方法。

     

RunTaskAsync提供了一个替代方法,它将TaskCompletionSource与RunAsync结合使用,以返回一个可以从后台线程中等待的Task,从而暂停执行,直到UI任务完成。

     

因为RunTaskAsync是一个扩展方法,所以你将它称为Dispatcher上的方法:var result = await Dispatcher.RunTaskAsync(async()=> {...; return value;});

using System;
using System.Threading.Tasks;
using Windows.UI.Core;

public static class DispatcherTaskExtensions
{
    public static async Task<T> RunTaskAsync<T>(this CoreDispatcher dispatcher, 
        Func<Task<T>> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal)
    {
        var taskCompletionSource = new TaskCompletionSource<T>();
        await dispatcher.RunAsync(priority, async () =>
        {
            try
            {
                taskCompletionSource.SetResult(await func());
            }
            catch (Exception ex)
            {
                taskCompletionSource.SetException(ex);
            }
        });
        return await taskCompletionSource.Task;
    }

    // There is no TaskCompletionSource<void> so we use a bool that we throw away.
    public static async Task RunTaskAsync(this CoreDispatcher dispatcher,
        Func<Task> func, CoreDispatcherPriority priority = CoreDispatcherPriority.Normal) => 
        await RunTaskAsync(dispatcher, async () => { await func(); return false; }, priority);
}
  

是否有必要锁定多个线程通过调度程序访问同一个uwp组件的代码段?

您不必添加锁。 Dispatcher.RunTaskAsync请求不会在其他代码的中间运行(这就是它们的全部内容)。

答案 1 :(得分:0)

这解决了这个问题:

.as-console-wrapper { max-height: 100%!important; top: 0; }

修订后的代码

private async Task  DisplayProgess(string message)
{
    await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
    {                
        lsvInvSynchProgress.Items.Add($"{message} - {DateTime.Now}");
     });
}