Invokehelper: Modify the attributes of the main interface control with multiple threads and call the method.

Source: Internet
Author: User

Byoy 2012

Source code: Click to download

The following is an animation that demonstrates that the operations on the main interface are not affected in the case of multiple threads (Infinite Loop + thread. Sleep.

Multithreading is a common technology that improves program running efficiency and performance. With the development of our learning work, multithreading is more or less involved in programming. Most of the time, our operation mode is to process data in the background thread, calculate the result, and then update the display in the foreground interface (GUI.

In. NET Framework, cross-thread access to form controls is not allowed to ensure thread security and avoid access competition. If the access is forcibly accessed, an invalidoperationexception exception is thrown, for example:

To implement cross-thread access to controls,. NET Framework provides the invokerequired attribute and invoke method for each control. By using these techniques, we can directly modify the interface in other threads. It seems very simple, but there are a lot of code to be written in each call, and you need to handle various exceptions on your own. The following is a typical Call example:

public void DoWork(){    if (control.InvokeRequired)    {        control.Invoke(DoWork);    }    else    {        // do work    }}

For ease of use, I encapsulated the implementation details. Here I will provide an invokehelper class, which can be used to conveniently call the main interface control method across threads and obtain/set control attributes.

The implementation of this class is very simple and there are about 150 lines of valid Code. There are three main methods:

1. Invoke

This method can call a method of the main interface control and return the method execution result. The usage is as follows:

Invokehelper. Invoke (<control>, "<Method Name>", <parameter> );

The "parameter" is the parameter list and supports 0 or more parameters.

2. Get

This method can obtain a property of the main interface control. The usage is as follows:

Invokehelper. Get (<control>, "<attribute name> ");

3. Set

This method can be used to set a property of the main interface control. The usage is as follows:

Invokehelper. Set (<control>, "<attribute name>", <attribute value> );

The following is the implementation code of the entire class. The end of this article is an example for demonstration.

/******************************************************************************* * InvokeHelper.cs * A thread-safe control invoker helper class. * ----------------------------------------------------------------------------- * Project:Conmajia.Controls * Author:Conmajia * Url:conmajia@gmail.com * History: *      4th Aug., 2012 *      Added support for "Non-control" controls (such as ToolStripItem). *       *      4th Aug., 2012 *      Initiated. ******************************************************************************/using System;using System.Collections.Generic;using System.Reflection;using System.Text;using System.Windows.Forms;namespace InvokerHelperDemo{    /// <summary>    /// A thread-safe control invoker helper class.    /// </summary>    public class InvokeHelper    {        #region delegates        private delegate object MethodInvoker(Control control, string methodName, params object[] args);        private delegate object PropertyGetInvoker(Control control, object noncontrol, string propertyName);        private delegate void PropertySetInvoker(Control control, object noncontrol, string propertyName, object value);        #endregion        #region static methods        // helpers        private static PropertyInfo GetPropertyInfo(Control control, object noncontrol, string propertyName)        {            if (control != null && !string.IsNullOrEmpty(propertyName))            {                PropertyInfo pi = null;                Type t = null;                if (noncontrol != null)                    t = noncontrol.GetType();                else                    t = control.GetType();                pi = t.GetProperty(propertyName);                if (pi == null)                    throw new InvalidOperationException(                        string.Format(                        "Can't find property {0} in {1}.",                        propertyName,                        t.ToString()                        ));                return pi;            }            else                throw new ArgumentNullException("Invalid argument.");        }        // outlines        public static object Invoke(Control control, string methodName, params object[] args)        {            if (control != null && !string.IsNullOrEmpty(methodName))                if (control.InvokeRequired)                    return control.Invoke(                        new MethodInvoker(Invoke),                        control,                        methodName,                        args                        );                else                {                    MethodInfo mi = null;                    if (args != null && args.Length > 0)                    {                        Type[] types = new Type[args.Length];                        for (int i = 0; i < args.Length; i++)                        {                            if (args[i] != null)                                types[i] = args[i].GetType();                        }                        mi = control.GetType().GetMethod(methodName, types);                    }                    else                        mi = control.GetType().GetMethod(methodName);                    // check method info you get                    if (mi != null)                        return mi.Invoke(control, args);                    else                        throw new InvalidOperationException("Invalid method.");                }            else                throw new ArgumentNullException("Invalid argument.");        }        public static object Get(Control control, string propertyName)        {            return Get(control, null, propertyName);        }        public static object Get(Control control, object noncontrol, string propertyName)        {            if (control != null && !string.IsNullOrEmpty(propertyName))                if (control.InvokeRequired)                    return control.Invoke(new PropertyGetInvoker(Get),                        control,                        noncontrol,                        propertyName                        );                else                {                    PropertyInfo pi = GetPropertyInfo(control, noncontrol, propertyName);                    object invokee = (noncontrol == null) ? control : noncontrol;                    if (pi != null)                        if (pi.CanRead)                            return pi.GetValue(invokee, null);                        else                            throw new FieldAccessException(                                string.Format(                                "{0}.{1} is a write-only property.",                                invokee.GetType().ToString(),                                propertyName                                ));                    return null;                }            else                throw new ArgumentNullException("Invalid argument.");        }        public static void Set(Control control, string propertyName, object value)        {            Set(control, null, propertyName, value);        }        public static void Set(Control control, object noncontrol, string propertyName, object value)        {            if (control != null && !string.IsNullOrEmpty(propertyName))                if (control.InvokeRequired)                    control.Invoke(new PropertySetInvoker(Set),                        control,                        noncontrol,                        propertyName,                        value                        );                else                {                    PropertyInfo pi = GetPropertyInfo(control, noncontrol, propertyName);                    object invokee = (noncontrol == null) ? control : noncontrol;                    if (pi != null)                        if (pi.CanWrite)                            pi.SetValue(invokee, value, null);                        else                            throw new FieldAccessException(                                string.Format(                                "{0}.{1} is a read-only property.",                                invokee.GetType().ToString(),                                propertyName                                ));                }            else                throw new ArgumentNullException("Invalid argument.");        }        #endregion    }}

The following is an example for demonstration. In this example, a thread with a permanent loop is created, and the interface is displayed every 500 milliseconds. The main code is as follows:

Thread t;private void button1_Click(object sender, EventArgs e){    if (t == null)    {        t = new Thread(multithread);        t.Start();        label4.Text = string.Format(            "Thread state:\n{0}",            t.ThreadState.ToString()            );    }}public void DoWork(string msg){    this.label3.Text = string.Format("Invoke method: {0}", msg);}int count = 0;void multithread(){    while (true)    {        InvokeHelper.Set(this.label1, "Text", string.Format("Set value: {0}", count));        InvokeHelper.Set(this.label1, "Tag", count);        string value = InvokeHelper.Get(this.label1, "Tag").ToString();        InvokeHelper.Set(this.label2, "Text",            string.Format("Get value: {0}", value));        InvokeHelper.Invoke(this, "DoWork", value);        Thread.Sleep(500);        count++;    }}

For detailed code, see the source code provided earlier. The running effect is normal. Although thread t is an infinite loop thread, the main interface is not blocked and operations are normal.

References

[1] Sergiu josan, making controls thread-safely, May 2009

[2] vicob, extension of safeinvoke, July 2010

Byoy 2012

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.