在常规WinAPI中,您可以使用PostMessage向应用程序内的窗口发送消息,它不会等待消息被处理,它会立即返回。
现在,在我的窗口中,我收到了这条消息,它在同一个UI线程中调用,我可以在这个线程中操作一些其他的UI控件。
如何在.NET WinForms中模拟此行为?
我知道我可以使用Delegate.BeginInvoke,它将异步调用我的方法,但它不会在同一个UI线程中执行,并且任何对UI控件的访问都会引发异常。我知道我可以使用Control.Invoke来改变该方法中的UI,但是编写代码太多了,我希望不用担心这一点,并以与WinAPI相同的方式工作。
我有这样一个代码
public delegate void DoDelegate();
private DoDelegate d;
public Form1()
{
InitializeComponent();
d = new DoDelegate(Do);
}
private void button1_Click(object sender, EventArgs e)
{
d.BeginInvoke(ar =>
{
AsyncResult result = (AsyncResult)ar;
DoDelegate dd = (DoDelegate)result.AsyncDelegate;
dd.EndInvoke(ar);
}, null);
}
public void Do()
{
Action a = () =>
{
for (int i = 0; i < 10; i++)
{
label1.Text = "Item " + i;
Thread.Sleep(1000);
}
};
if (InvokeRequired)
Invoke(a);
else a();
}即使在单独的线程中被调用,它也会阻塞主线程。我知道为什么,因为我在整个方法上使用了Control.Invoke,并且我应该只在设置.Text属性时使用它,但同样,这太多了,很容易忘记use Invoke,然后所有的崩溃。
那么,基本上,我如何调用异步方法,这样在没有调用机制的情况下访问UI不会产生任何问题,就像我使用PostMessage所做的那样?
想法?
发布于 2015-01-15 17:03:52
我使用这个扩展方法:
public static void InvokeIfRequired(this Control control, Action action)
{
if (control.InvokeRequired)
control.Invoke(action);
else
action();
}我在访问UI的任何多线程代码上使用它。在您的示例中,它将如下所示:
label1.InvokeIfRequired(() => { label1.Text = "Item " + i });请注意,如果您广泛地将其用于对控件的单个更改,则使用扩展方法的重载可能是明智的,例如:
public static void InvokeIfRequired(this Control control, Action<Control> action)
{
if (control.InvokeRequired)
control.Invoke(new Action(() => action(control)));
else
action(control);
}所以你可以这样做:
label1.InvokeIfRequired(x => { x.Text = "Item " + i });不必重复对lambda表达式的控制
https://stackoverflow.com/questions/27958569
复制相似问题