开发者

Accessing Button created by GUI Worker Thread from another thread in WinForms application

开发者 https://www.devze.com 2023-02-15 19:23 出处:网络
Accessing a button created in the GUI worker thread from a different thr开发者_如何学编程ead in C# - windows forms applicationIf you\'re using Windows Forms, you generally want to use Control.BeginInv

Accessing a button created in the GUI worker thread from a different thr开发者_如何学编程ead in C# - windows forms application


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.


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


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


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]

0

精彩评论

暂无评论...
验证码 换一张
取 消