C# 任务。运行和UI进度更新

C# 任务。运行和UI进度更新,c#,asynchronous,progress,C#,Asynchronous,Progress,此代码段来自,并给出了使用Task.Run时如何报告进度的示例。我想知道为什么在更新UI时没有跨线程问题,我的意思是为什么不需要调用 private async void button2_Click(object sender, EventArgs e) { var progressHandler = new Progress<string>(value => { label2.Text = value; }); var prog

此代码段来自,并给出了使用Task.Run时如何报告进度的示例。我想知道为什么在更新UI时没有跨线程问题,我的意思是为什么不需要调用

private async void button2_Click(object sender, EventArgs e)
{
    var progressHandler = new Progress<string>(value =>
    {
        label2.Text = value;
    });
    var progress = progressHandler as IProgress<string>;
    await Task.Run(() =>
    {
        for (int i = 0; i != 100; ++i)
        {
            if (progress != null)
                progress.Report("Stage " + i);
            Thread.Sleep(100);
        }
    });
    label2.Text = "Completed.";
}
private async void按钮2\u单击(对象发送方,事件参数e)
{
var progressHandler=新进度(值=>
{
label2.Text=值;
});
var progress=progressHandler作为IProgress;
等待任务。运行(()=>
{
对于(int i=0;i!=100;++i)
{
如果(进度!=null)
进度报告(“阶段”+i);
睡眠(100);
}
});
label2.Text=“已完成。”;
}
Progress
在实例化当前的
synchronizationcontext
时捕获它。无论何时调用
Report
,它都会秘密地将其委托给捕获的上下文。在本例中,捕获的上下文是UI,这意味着不会发生异常。

进程构造函数捕获当前的
同步上下文
对象

SynchronizationContext
类是一种抽象所涉及线程模型细节的工具。也就是说,在Windows窗体中,它将使用
Control.Invoke
,在WPF中,它将使用
Dispatcher.Invoke
,等等

调用
progress.Report
对象时,
progress
对象本身知道应该使用捕获的
SynchronizationContext
运行其委托


换句话说,它之所以有效,是因为
Progress
设计用来处理这个问题,而开发人员不必明确地说出来。

您似乎感到困惑,因为这个跨线程机制的一部分是隐藏在开发人员的视线之外的,所以您只需“使用它”:

我们引入了IProgress接口,使您能够创建 展示进步的经验。此接口公开一个报告(T) 方法,异步任务调用该方法以报告进度。你揭发这个 接口,调用方必须 提供实现此接口的对象。共同完成任务 调用方创建了一个非常有用的链接(可以在 不同的线程)

我们还提供了Progress类,它是 我的进步。我们鼓励您在工作中使用进步 实现,因为它处理有关保存的所有簿记 以及恢复同步上下文。进展既暴露了一个问题,也暴露了另一个问题 事件和操作回调,当任务 报告进展情况。此模式使您能够编写简单 对发生的进度更改作出反应。一起,我前进 Progress提供了一种从服务器传递进度信息的简单方法 将后台任务添加到UI线程


还有一件事需要说明:进度通知将在部分工作完成后调用,而不仅仅是在那一刻。因此,如果您的UI线程处于空闲状态,并且您有空闲的CPU核心,那么延迟几乎为零。如果您的UI线程正忙,则在UI线程返回空闲状态之前(无论您的计算机有多少空闲CPU内核),不会调用通知。

您知道此线程的优先级吗?ie:Normal、Background、ApplicationIdle等@Kelly调度程序优先级正常。请参阅此处的备注部分@newbieguiy字符串连接自动调用ToString()方法