从 WinForms 应用程序中的另一个线程访问由 GUI 工作线程创建的按钮

发布于 2024-10-20 19:25:15 字数 53 浏览 2 评论 0原文

从 C# 中的不同线程访问在 GUI 工作线程中创建的按钮 - Windows 窗体应用程序

Accessing a button created in the GUI worker thread from a different thread in C# - windows forms application

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

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

发布评论

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

评论(4

深爱成瘾 2024-10-27 19:25:15

如果您使用的是 Windows 窗体,通常需要使用 Control.BeginInvokeControl .调用

如果您使用的是 WPF,则需要使用适当的 Dispatcher< /code>并再次使用其 BeginInvoke< /code>调用方法。

(基本上,Invoke 将阻塞,直到委托在正确的线程中执行;BeginInvoke 不会。)

另一种选择是使用 BackgroundWorker,但是除非您只是报告进度,否则我倾向于使用上述选项之一。

If you're using Windows Forms, you generally want to use Control.BeginInvoke or Control.Invoke.

If you're using WPF, you need to use the appropriate Dispatcher and again use its BeginInvoke or Invoke methods.

(Basically Invoke will block until the delegate has executed in the right thread; BeginInvoke won't.)

Another alternative is to use BackgroundWorker, but unless you're just reporting progress, I tend to use one of the options above.

み格子的夏天 2024-10-27 19:25:15

下面是一个可用于从另一个线程设置属性的函数:

using System.Reflection;

...

    delegate void SetControlValueCallback(Control oControl, string propName, object propValue);
    private void SetControlPropertyValue(Control oControl, string propName, object propValue)
    {
        if (oControl.InvokeRequired)
        {
            SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
            oControl.Invoke(d, new object[] { oControl, propName, propValue });
        }
        else
        {
            Type t = oControl.GetType();
            PropertyInfo[] props = t.GetProperties();
            foreach (PropertyInfo p in props)
            {
                if (p.Name.ToUpper() == propName.ToUpper())
                {
                    p.SetValue(oControl, propValue, null);
                }
            }
        }
    }

用法示例

SetControlPropertyValue(Button1, "Enabled", false);

Here's a function you can use to set properties from another thread:

using System.Reflection;

...

    delegate void SetControlValueCallback(Control oControl, string propName, object propValue);
    private void SetControlPropertyValue(Control oControl, string propName, object propValue)
    {
        if (oControl.InvokeRequired)
        {
            SetControlValueCallback d = new SetControlValueCallback(SetControlPropertyValue);
            oControl.Invoke(d, new object[] { oControl, propName, propValue });
        }
        else
        {
            Type t = oControl.GetType();
            PropertyInfo[] props = t.GetProperties();
            foreach (PropertyInfo p in props)
            {
                if (p.Name.ToUpper() == propName.ToUpper())
                {
                    p.SetValue(oControl, propValue, null);
                }
            }
        }
    }

Example Usage

SetControlPropertyValue(Button1, "Enabled", false);
怎会甘心 2024-10-27 19:25:15

您必须检查是否可以从您所在的线程访问该控件。
为此,您有一个名为“InvokeRequired”的属性。
例如: mybutton.InvokeRequired 。

如果为 true,则需要从另一个线程(可以访问控件的线程)调用该方法。

下面是 MSDN 上的一个示例,对其进行了详细解释:
http://msdn.microsoft.com/en -us/library/ms171728%28v=vs.80%29.aspx

You must check if you can access the control from the thread you're in.
To do that you have a property called "InvokeRequired".
For example: mybutton.InvokeRequired .

If true, you need to invoke the method from another thread (the thread that can access the control).

Here's an example from MSDN that explains it throughly:
http://msdn.microsoft.com/en-us/library/ms171728%28v=vs.80%29.aspx

鼻尖触碰 2024-10-27 19:25:15

该解决方案在我创建的应用程序中完美运行,该应用程序几乎因如此多的此类异步调用而爆炸,以保持 UI 响应能力!

在深入研究了一些内部结构之后,我解释了我所发现的内容。它主要鼓励对三个领域的思考。

  1. 异步和多个衍生线程的后果?
  2. 这么小的代码块是如何实现的呢?
  3. 幕后发生了什么?

对耗时资源的同步调用可能会导致 UI 无响应。例如。对处理无数记录的 SP 的数据库调用。在这种情况下,**异步**对耗时资源的调用可以使 UI 线程在后台运行资源请求时保持响应。耗时的后台进程完成后,更新主 UI 资源会出现这样的错误。

Dot Net 框架尊重基于线程的资源所有权。(例如,在模板的典型 Windows 表单应用程序中,主线程拥有表单上的所有控件和表单本身,即从调用到 new Form1() 的所有内容)<线程间同步,允许线程将工作单元委托给彼此,同时保留所有权控制。 (例如,在耗时的数据库调用之后,您可能想要更新 UI 上的进度条控件)

它内部如何工作?

在内部,您的 Windows 窗体应用程序创建并安装 WindowsFormsSynchronizationContext 作为当前上下文您创建表单的实例,甚至为表单内的对象创建实例(通常使用设计器代码创建)。这是接口 [ISynchronizeInvoke] 的 WindowsForms 实现,它具有 BeginInvoke 和 EndInvoke 异步方法以及 Invoke 同步方法。 (您可以自定义 Windows 应用程序以使用线程池同步上下文而不是 Windows 及其 ISynchronizeInvoke 的不同具体实现)。

我可以将其扩展到我自己的自定义类和对象吗?

是的,您可以通过实现 ISynchronizeInvoke 接口并提供具体的实现来在您的类/对象上实现异步操作
BeginInvoke 和 EndInvoke 方法。

正如 msdn 杂志所说,这一切都与同步上下文有关,链接在此处


从更广泛的角度和更高的抽象级别提出问题

(SynchronizationContext 或 InvokeRequired)
[http://social.msdn.microsoft.com/Forums/en-US/1218c86e-fa9b-45a6-93b0-5e27616a6c21/shoud-i-use-synchronizationcontext-or-invokerequired-?论坛=异步]

This solution worked flawless in an application I created that practically explodes with so many such asynchronous calls, to keep the UI Responsive!

After digging into some of the internals I have accounted what I found out. It would predominantly encourage thought on 3 areas.

  1. Consequences of Async and multiple spawned threads?
  2. How is it Pulled off with such a small block of Code?
  3. What is happening behind the scene?

A Synchronous call to a time taking resource might render the UI unresponsive. For eg. A DB call to a SP that processes bzillion records. In such a case **Async**hronous call to the time taking resource keeps the UI thread responsive while running the resource request in the background. After the time-consuming background process finishes, updating the primary UI resource gives u such an error.

The Dot Net framework respects thread based ownership of resources.(eg. In your typical windows forms application from template, the primary thread owns all the controls on the form and the form itself, viz everything from that call to new Form1()) Inter-thread synchronization, would let threads to delegate units of work to one another whilst retaining the ownership control. (Eg. After the time consuming DB call you might want to update the progress bar control on the UI)

How does it work internally?

Internally your Windows Forms application creates and installs the WindowsFormsSynchronizationContext as the current context when you create an instance of the form and even for the objects within the form (usually created using the designer code). This is a WindowsForms' implementation of interface [ISynchronizeInvoke] which has the BeginInvoke and EndInvoke Async methods along with Invoke Synchronous Method. (You can customize your Windows application to use the Threadpool Synchronization Context instead of Windows' and its a different concrete implementation of ISynchronizeInvoke).

Can I Extend this to my own custom classes and objects?

Yes, You can have an asynchronous operation pulled off on your class / object by implementing the ISynchronizeInvoke interface and provide concrete implementations of
The BeginInvoke and the EndInvoke methods.

Its all about synchronization context as the msdn magazine puts it, link here


Related question at a slightly broader perspective and a higher level of abstraction

(SynchronizationContext or InvokeRequired)
[http://social.msdn.microsoft.com/Forums/en-US/1218c86e-fa9b-45a6-93b0-5e27616a6c21/shoud-i-use-synchronizationcontext-or-invokerequired-?forum=async]

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