Label.Text = Struct.Value(Microsoft.VisualStudio.Debugger.Runtime.CrossThreadMessagingException)

时间:2011-01-09 16:43:06

标签: c# multithreading iasyncresult

我有一个应用程序,我正在研究从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;
}

5 个答案:

答案 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);

您可以为同一类中的CheckBoxRadioButtons等其他内容创建多个类似的扩展程序。这样你就可以轻松记住并使用扩展方法。

当然你也可以创建这样的普通方法(注意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";
                });