我看了一遍,我找不到答案。 使用是否更好,更糟或无动于衷:
{
...
RefreshPaintDelegate PaintDelegate = new RefreshPaintDelegate(RefreshPaint);
Control.Invoke(PaintDelegate);
}
protected void RefreshPaint()
{
this.Refresh();
}
...或...
Task.Factory.StartNew(() =>
{
this.Refresh();
},
CancellationToken.None,
TaskCreationOptions.None,
uiScheduler);
答案 0 :(得分:3)
假设uiScheduler
是一个将委托调用到UI线程的调度程序,我会说在功能上,使用这两个是无关紧要的(除了对Control.Invoke的调用将阻塞直到调用完成,而对Task
的调用不会,但是,您始终可以使用Control.BeginInvoke
使它们在语义上等效。
从语义的角度来看,我会说使用Control.Invoke(PaintDelegate)
是一种更好的方法;当你使用Task
时,你正在做一个隐含的声明,你想要执行一个工作单元,并且通常,该工作单元具有与其他工作单元一起安排的上下文,它是决定如何工作的调度程序该工作是委派的(通常,它是多线程的,但在这种情况下,它被封送到UI线程)。还应该说,uiScheduler
和Control
之间没有明确的联系,它与UI线程相关联,调用应该是一个(通常,它们都是相同的,但它是可能有多个UI线程,虽然非常罕见)。
但是,在使用Control.Invoke
时,您想要做的意图是明确的,您想要调用Control
正在为消息打开的UI线程的调用,并且此调用指示那很完美。
但我认为最好的选择是使用SynchronizationContext
实例;它抽象出你需要同步调用该上下文的事实,而不是其他两个选项,这两个选项要么对调用中的意图不明确(Task
),要么非常具体地说明它的完成方式(Control.Invoke
)。
答案 1 :(得分:0)
不一样。第一个版本将阻止调用线程,直到UI线程准备好调用该方法。对于非阻止版本,您应该使用Control.BeginInvoke
,它也会立即返回。
除此之外(如果您将Task与线程池线程进行比较),使用它们几乎没有区别。
[编辑]
在这种情况下,Task.Factory.StartNew
和Control.BeginInvoke
之间没有区别(但不像我上面写的那样Invoke
),因为只有一个GUI线程可以执行你的代码。无论你使用其中任何一个调用多少次调用,当UI线程空闲时,它们仍将按顺序执行。