我有一个应用程序,我正在研究从ISP(下载配额)的民意调查使用情况。我试过通过'新线程(ThreaProc)'来解决这个问题,但这样做不起作用,现在尝试基于IAsyncResult的方法做同样的事情......我不知道如何纠正,请帮助?< / p>
需要知道:
// Global
public delegate void AsyncPollData(ref POLLDATA pData);
// Class scope:
private POLLDATA pData;
private void UpdateUsage()
{
AsyncPollData PollDataProc = new AsyncPollData(frmMain.PollUsage);
IAsyncResult result = PollDataProc.BeginInvoke(ref pData,
new AsyncCallback(UpdateDone), PollDataProc);
}
public void UpdateDone(IAsyncResult ar)
{
AsyncPollData PollDataProc = (AsyncPollData)ar.AsyncState;
PollDataProc.EndInvoke(ref pData, ar);
// The Exception occurs here:
lblStatus.Text = pData.LastError;
}
public static void PollUsage(ref POLLDATA PData)
{
PData.LastError = "Some string";
return;
}
答案 0 :(得分:3)
lblStatus.Invoke(delegate() { lblStatus.Text = pData.LastError; });
跨线程更新值不安全,因此编译器会向您发出警告。通过使用Invoke()
,将在GUI线程中调用传递的代码,因此您将更新GUI线程中的GUI值,这是安全的。
答案 1 :(得分:3)
你可以创建一个新类并创建这样的扩展:
public static class ThreadSafeHelpers {
public static void SetText(this Label varLabel, string newText) {
if (varLabel.InvokeRequired) {
varLabel.BeginInvoke(new MethodInvoker(() => SetText(varLabel, newText)));
} else {
varLabel.Text = newText;
}
}
}
然后你在代码中的任何地方使用它:
lblStatus.SetText(pData.LastError);
您可以为同一类中的CheckBox
,RadioButtons
等其他内容创建多个类似的扩展程序。这样你就可以轻松记住并使用扩展方法。
当然你也可以创建这样的普通方法(注意Label旁边没有this
):
public static class ThreadSafeHelpers {
public static void SetText(Label varLabel, string newText) {
if (varLabel.InvokeRequired) {
varLabel.BeginInvoke(new MethodInvoker(() => SetText(varLabel, newText)));
} else {
varLabel.Text = newText;
}
}
}
并使用如下代码:
ThreadSafeHelpers.SetText(varLabel, newText);
答案 2 :(得分:1)
您的控件是在线程A [绘制和处理Windows消息的那个]上创建的,因此线程B [Monitor]无法访问它[Hurray for race-conditions],请看一下:
How to update the GUI from another thread in C#?
干杯
答案 3 :(得分:0)
[更多说明:我使用的是.NET 3.0]
即使我使用'如何从C#中的另一个线程更新GUI'中描述的方法?该函数的其他部分(UpdateDone)失败(即使与线程无关的部分也会失败,因为类的某些部分已在当前线程之外访问)。
// This now works
DelegationClass.SetPropertyThreadSafe(lblStatus, () => lblStatus.Text, pData.LastError);
// Later on down the function, both objects are a member of the same class, the variable icon was never touched by another thread.
this.Icon = icon;
// An unhandled exception of type 'System.InvalidOperationException' occurred in System.Windows.Forms.dll
// Additional information: Cross-thread operation not valid: Control 'frmMain' accessed from a thread other than the thread it was created on.
如果我错了,请纠正我,但是因为调用了EndInvoke,所以线程应该已经终止。因此,不应存在“竞争条件”;所有数据都由主线程再次拥有,我可以自由地使用数据做我想做的事情......?
我在整个班级使用的结构中有多个项目;有没有更好的方法呢?你会怎么做?
基本限制:
*单个函数进行数据轮询,其目的不是让它阻止UI交互
*因此该功能必须是异步
*主要的Form类(frmMain)需要通知(Async)完成相关功能并根据需要更新它的GUI。
*当然主要是,函数获得的数据需要frmMain
(上帝,使用C ++进行线程化非常简单)
答案 4 :(得分:0)
线程睡眠方法可能对您有用
Thread.Sleep(100);
this.Invoke((MethodInvoker)delegate
{
txtChatBox.Text += msgReceived.strMessage + "\r\n";
});