Multithreading 为什么在Task.Run()中更新UI

Multithreading 为什么在Task.Run()中更新UI,multithreading,asynchronous,xamarin.forms,task,threadpool,Multithreading,Asynchronous,Xamarin.forms,Task,Threadpool,我正在开发一个Xamarin.Forms应用程序,其中我显示了一个标签,在启动计时器后,它每秒钟更新一次文本。标签的文本值绑定到名为“TimerValue”的ViewModel属性。它用于显示音频输入的录制持续时间。计时器方法如下所示: /// <summary> /// The start recorder. /// </summary> private void StartTimer() { var st

我正在开发一个Xamarin.Forms应用程序,其中我显示了一个标签,在启动计时器后,它每秒钟更新一次文本。标签的文本值绑定到名为“TimerValue”的ViewModel属性。它用于显示音频输入的录制持续时间。计时器方法如下所示:

    /// <summary>
    ///     The start recorder.
    /// </summary>
    private void StartTimer()
    {
        var stopwatch = new Stopwatch();
        stopwatch.Start();

        Device.StartTimer(
            new TimeSpan(0, 0, 0, 1, 0),
            () =>
                {
                    if (this.isRecording)
                    {
                        this.TimerValue = stopwatch.Elapsed.Seconds;
                        return true;
                    }

                    stopwatch.Stop();
                    this.TimerValue = 0;
                    return false;
                });
    }
//
///启动录音机。
/// 
私有void StartTimer()
{
var stopwatch=新秒表();
秒表。开始();
设备启动程序(
新的时间跨度(0,0,0,1,0),
() =>
{
如果(此.isRecording)
{
this.TimerValue=stopwatch.appeased.Seconds;
返回true;
}
秒表;
this.TimerValue=0;
返回false;
});
}
计时器在任务内启动。在UI事件上调用的运行(GestureRecognizer.Tapped):

wait Task.Run(()=>this.StartTimer()).configurewait(false)

这段代码可以工作,但为什么呢?Run在线程池上启动一个新线程,TimerValue位于UI线程上。在这种情况下,我是否应该调用Xamarin.Forms.Device.BeginInvokeOnMainThread来更新UI


如果我在Task.Run中设置了UI绑定属性,为什么UI会得到更新?

Device.StartTimer位于Xamarin.Forms命名空间中。这使得它很可能是一个同步计时器,类似于WPF的Dispatchermer和Winforms的计时器。这使得它非常像是在UI线程上滴答作响。或者永远不要滴答声,你会知道的。这些文件对这件事太模糊了。好吧,这只鞋很合脚。好吧,我以为它在线上滴答滴答地响着它的名字。。。因为如果我不调用Task.Run来启动计时器,如果我切换页面(整个应用程序使用TabbedPage布局来显示其数据),它将停止工作。此外,WPF将允许一些跨线程更新。我不知道Xamarin也会这么做。他们会扔并不意味着他们必须扔。(在我看来,跨线程更新仍然是一个坏主意,即使特定平台实现恰好允许这种更新)。@StephenCleary因此,尽管我的代码在本示例中运行,但您是否建议使用Device.beginInvokeMainThread调用UI线程上的更新?我使用
等待
获取结果/错误,
IProgress
用于进度更新,而
SynchronizationContext
用于订阅。看起来您的是订阅模型,所以我会使用
SynchronizationContext
.Device.StartTimer位于Xamarin.Forms命名空间中。这使得它很可能是一个同步计时器,类似于WPF的Dispatchermer和Winforms的计时器。这使得它非常像是在UI线程上滴答作响。或者永远不要滴答声,你会知道的。这些文件对这件事太模糊了。好吧,这只鞋很合脚。好吧,我以为它在线上滴答滴答地响着它的名字。。。因为如果我不调用Task.Run来启动计时器,如果我切换页面(整个应用程序使用TabbedPage布局来显示其数据),它将停止工作。此外,WPF将允许一些跨线程更新。我不知道Xamarin也会这么做。他们会扔并不意味着他们必须扔。(在我看来,跨线程更新仍然是一个坏主意,即使特定平台实现恰好允许这种更新)。@StephenCleary因此,尽管我的代码在本示例中运行,但您是否建议使用Device.beginInvokeMainThread调用UI线程上的更新?我使用
等待
获取结果/错误,
IProgress
用于进度更新,而
SynchronizationContext
用于订阅。看起来你的是订阅模式,所以我会使用
SynchronizationContext