从WinForms应用程序中的另一个线程访问由GUI Worker Thread创建的Button

时间:2011-03-07 12:54:19

标签: c# winforms multithreading

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

4 个答案:

答案 0 :(得分:6)

如果您使用的是Windows表单,则通常需要使用Control.BeginInvokeControl.Invoke

如果您使用的是WPF,则需要使用相应的Dispatcher并再次使用其BeginInvokeInvoke方法。

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

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

答案 1 :(得分:5)

这是一个可用于设置其他线程属性的函数:

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

答案 2 :(得分:3)

您必须检查是否可以从您所在的主题访问该控件。 要做到这一点,你有一个名为“InvokeRequired”的属性。 例如:mybutton.InvokeRequired。

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

这是MSDN的一个例子,它解释了它: http://msdn.microsoft.com/en-us/library/ms171728%28v=vs.80%29.aspx

答案 3 :(得分:1)

这个解决方案在我创建的应用程序中运行完美,它实际上爆炸了很多这样的异步调用,以保持UI响应!

在深入了解一些内部结构后,我已经解释了我发现的内容。它将主要鼓励3个领域的思考。

  1. 异步和多个衍生线程的后果?
  2. 这么小的代码块如何拉下
  3. 幕后发生了什么
  4. 对获取时间资源的同步调用可能会导致UI无响应。例如。数据库调用SP处理bzillion记录。在这种情况下**异步**对时间占用资源的hronous调用使UI线程在后台运行资源请求时保持响应。在耗时的后台进程完成后,更新主UI资源会给您带来这样的错误。

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

    内部如何运作?

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

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

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

    所有关于同步上下文的内容正如msdn杂志所说,link here


    相对较宽的视角和更高的抽象层次

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