1

我有一个正在处理的应用程序,该应用程序从 ISP(下载配额)轮询使用情况。我已经尝试通过'new Thread(ThreaProc)'进行线程化,但没有奏效,现在尝试基于 IAsyncResult 的方法来做同样的事情......我不知道如何纠正,请帮忙?

需要知道的:

// 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;
}
4

5 回答 5

3
lblStatus.Invoke(delegate() { lblStatus.Text = pData.LastError; });

跨线程更新值是不安全的,因此编译器会警告您。通过使用Invoke()传递的代码将在 GUI 线程中调用,因此您在 GUI 线程中更新 GUI 值,这是安全的。

于 2011-01-09T16:47:10.213 回答
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这样您就可以轻松记住和使用扩展方法。

当然你也可以像这样创建一个普通的方法(注意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);
于 2011-01-09T19:40:51.290 回答
1

您的控件是在线程 A [绘制和处理 Windows 消息的那个] 上创建的,因此线程 B [监视器] 无法访问它 [为竞争条件万岁],看看这个:

如何从 C# 中的另一个线程更新 GUI?

干杯

于 2011-01-09T16:47:26.817 回答
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 交互。
* 因此该函数必须是异步
的 * 主窗体类 (frmMain) 需要通知 (Async) 有关函数的完成并根据需要更新它的 GUI。
* 当然,首先,函数获得的数据需要容易被 frmMain 的成员访问

(天哪,线程在 C++ 中要简单得多)

于 2011-01-09T17:31:32.837 回答
0

线程睡眠方法可能对你有用

                Thread.Sleep(100);
                this.Invoke((MethodInvoker)delegate
                {

                    txtChatBox.Text += msgReceived.strMessage + "\r\n";
                });
于 2013-05-14T05:21:28.623 回答