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

发布于 2024-10-11 06:33:04 字数 816 浏览 7 评论 0原文

我正在开发一个应用程序,用于轮询 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;
}

I have an app that I'm working on that polls usage from an ISP (Download quota). I've tried threading this via 'new Thread(ThreaProc)' but that didn't work, now trying an IAsyncResult based approach which does the same thing... I've got no idea on how to rectify, please help?

The need-to-know:

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

_失温 2024-10-18 06:33:04
lblStatus.Invoke(delegate() { lblStatus.Text = pData.LastError; });

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

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

Updating values across threads isn't safe so the compiler warns you. By using Invoke() the passed code will be called in the GUI thread, so you're updating a GUI value in the GUI thread, which is safe.

思慕 2024-10-18 06:33:04

您可以为自己创建一个新类并创建如下扩展:

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

You could create yourself a new class and create extensions like this:

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

And then u use this anywhere in your code like this:

lblStatus.SetText(pData.LastError);

You can create multiple similar extensions for other things like CheckBox, RadioButtons in same class. That way you can have an easy to remember and use extension methods.

Of course you could also create a normal method like this (notice lack of this next to Label):

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

and use the code like this:

ThreadSafeHelpers.SetText(varLabel, newText);
作死小能手 2024-10-18 06:33:04

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

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

干杯

Your control was created on thread A [The one that paints and handles windows messages] so thread B [Monitor] cannot access it [Hurray for race-conditions], take a look at this:

How to update the GUI from another thread in C#?

Cheers

坚持沉默 2024-10-18 06:33:04

[更多说明:我正在使用 .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) 相关功能的完成,并根据需要更新其 GUI。
* 当然,首先,函数获得的数据需要能够被 frmMain 的成员轻松访问

(天啊,使用 C++ 线程化要简单得多)

[More notes: I'm using .NET 3.0]

Even when I use the method described in 'How to update GUI from another thread in C#?' other parts of that function (UpdateDone) fails (Even parts that are nothing to do with threading fails because certain parts of the class have been accessed outside of the current thread).

// 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.

Correct me if I'm wrong, but since EndInvoke is called, the thread should have terminated. Therefore no "Race conditions" should exist; all data is owned by the primary thread again and I should be free to do what I want with the data...?

There are multiple items in that struct that I use throughout the class; Is there a better way of doing this? How would you do it?

Basic constraints:
* A single function does the data polling, the idea is not to let it block UI interaction.
* Therefore that function must be Asynchronous
* The main Form class (frmMain) needs to be notified (Async) of the completion of the function in question and update it's GUI as required.
* And of course primarily, that data obtained by the function needs to be easily accessible to the members of frmMain

(God, threading was so much simpler with C++)

新人笑 2024-10-18 06:33:04

线程睡眠方法可能适合你

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

                    txtChatBox.Text += msgReceived.strMessage + "\r\n";
                });

Thread Sleep method may be work for you

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

                    txtChatBox.Text += msgReceived.strMessage + "\r\n";
                });
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文