C# 使用asyc WAIT从事件更新UI
我试图理解如何在使用异步/等待模式时从事件更新UI。 下面是我在WinForm应用程序上使用的测试代码。我甚至不确定这样做是否正确。允许pwe_StatusUpdate方法更新UI需要什么?此时会抛出跨线程操作错误 谢谢你的阅读C# 使用asyc WAIT从事件更新UI,c#,asynchronous,async-await,C#,Asynchronous,Async Await,我试图理解如何在使用异步/等待模式时从事件更新UI。 下面是我在WinForm应用程序上使用的测试代码。我甚至不确定这样做是否正确。允许pwe_StatusUpdate方法更新UI需要什么?此时会抛出跨线程操作错误 谢谢你的阅读 // calling code ProcessWithEvents pwe = new ProcessWithEvents(); pwe.StatusUpdate += pwe_StatusUpdate; await pwe.Run();
// calling code
ProcessWithEvents pwe = new ProcessWithEvents();
pwe.StatusUpdate += pwe_StatusUpdate;
await pwe.Run();
void pwe_StatusUpdate(string updateMsg)
{
// Error Here: Cross-thread operation not valid: Control '_listBox_Output' accessed from a thread other than the thread it was created on.
_listBox_Output.Items.Add(updateMsg);
}
-
//具有长时间运行的进程和事件的类
公共委托无效状态UpdateHandler(字符串updateMsg);
公共类ProcessWithEvents
{
公共事件状态更新处理程序状态更新;
公共异步任务运行()
{
等待任务。运行(()=>
{
对于(int i=0;i<10;i++)
{
RaiseUpdateEvent(String.Format(“Update{0}”,i));
睡眠(500);
}
});
}
私有void RaiseUpdateEvent(字符串消息)
{
如果(状态更新!=null)
状态更新(msg);
}
}
-您应该使用
调用控制方法
。它在控件的线程中执行一些代码。您还可以检查invokererequired
属性,以检查是否需要调用Invoke
方法(它检查调用方是否位于与创建控件的线程不同的线程上)
简单的例子:
void SomeAsyncMethod()
{
// Do some work
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)(() =>
{
DoUpdateUI();
}
));
}
else
{
DoUpdateUI();
}
}
void DoUpdateUI()
{
// Your UI update code here
}
在某些情况下,在调用Invoke
方法之前,您应该检查Control
的IsHandleCreated
属性。如果IsHandleCreated
返回false,则需要等待控件句柄的创建//只需像这样声明一个委托即可
delegate void Add(string msg);
//然后声明委托方法,如下所示:
var add = new Add((msg) => {
_listBox_Output.Items.Add(msg);
});
//现在只需给代表打电话:
void pwe_StatusUpdate(string updateMsg)
{
_listBox_Output.Invoke(add,updateMsg);
}
简而言之,您的async
方法可以采用IProgress
,并且您的调用代码在该接口的实现中传递(通常是Progress
)
public类ProcessWithUpdates
{
公共异步任务运行(IProgress进程)
{
等待任务。运行(()=>
{
对于(int i=0;i<10;i++)
{
如果(进度!=null)
进度报告(String.Format(“Update{0}”,i));
睡眠(500);
}
});
}
}
//呼叫码
ProcessWithUpdates pwp=新的ProcessWithUpdates();
等待pwp运行(新进度(pwp_状态更新));
这里是另一个例子
async void DoExport()
{
var rMsg = "";
var t = await Task<bool>.Factory.StartNew(() => ExportAsMonthReport(LastMonth.Name, LastYear.Name, out rMsg));
if (t)
{
BeginInvoke((Action)(() =>
{
spinnerMain.Visible = false;
menuItemMonth.Enabled = true;
MetroMessageBox.Show(this, rMsg, "Export", MessageBoxButtons.OK, MessageBoxIcon.Information, 200);
}));
}
else
{
BeginInvoke((Action)(() =>
{
spinnerMain.Visible = false;
menuItemMonth.Enabled = true;
MetroMessageBox.Show(this, rMsg, "Export", MessageBoxButtons.OK, MessageBoxIcon.Error, 200);
}));
}
}
async void DoExport()
{
var rMsg=“”;
var t=wait Task.Factory.StartNew(()=>ExportAsMonthReport(lastmount.Name,lastwear.Name,out rMsg));
if(t)
{
开始(动作)(()=>
{
spinnerMain.Visible=假;
menuItemMonth.Enabled=true;
MetroMessageBox.Show(这个,rMsg,“导出”,MessageBoxButtons.OK,MessageBoxIcon.Information,200);
}));
}
其他的
{
开始(动作)(()=>
{
spinnerMain.Visible=假;
menuItemMonth.Enabled=true;
显示(这个,rMsg,“导出”,MessageBoxButtons.OK,MessageBoxIcon.Error,200);
}));
}
}
这与进度建议一样有效。我正在使用这两种方法,非常感谢。在使用异步模式时,您不应该自己实现这一点<代码>进度
已在创建它的SynchronizationContext上执行。简单解决方案。很好用。//调用代码
部分中的ProcessWithProgress
应该是ProcessWithUpdates
吗?
public class ProcessWithUpdates
{
public async Task Run(IProgress<string> progress)
{
await Task.Run(() =>
{
for (int i = 0; i < 10; i++)
{
if (progress != null)
progress.Report(String.Format("Update {0}", i));
Thread.Sleep(500);
}
});
}
}
// calling code
ProcessWithUpdates pwp = new ProcessWithUpdates();
await pwp.Run(new Progress<string>(pwp_StatusUpdate));
async void DoExport()
{
var rMsg = "";
var t = await Task<bool>.Factory.StartNew(() => ExportAsMonthReport(LastMonth.Name, LastYear.Name, out rMsg));
if (t)
{
BeginInvoke((Action)(() =>
{
spinnerMain.Visible = false;
menuItemMonth.Enabled = true;
MetroMessageBox.Show(this, rMsg, "Export", MessageBoxButtons.OK, MessageBoxIcon.Information, 200);
}));
}
else
{
BeginInvoke((Action)(() =>
{
spinnerMain.Visible = false;
menuItemMonth.Enabled = true;
MetroMessageBox.Show(this, rMsg, "Export", MessageBoxButtons.OK, MessageBoxIcon.Error, 200);
}));
}
}