多線程委派 转

一般我們在實作多線程存取主線程控制項屬性時,必須以委派方式來存取,否則就有可能會出現 InvalidOperationException 例外, 一般初學者總會犯這個錯誤,大都不知道需要委派的動作,總是在子線程用一行 textBox1.Text = "aaaaa" 就想改變控制項的屬性,卻 換來 InvalidOperationException 的錯誤,而在一般情況下委派的動作總不會 像 textBox1.Text = "aaaaa" 短短一行就這麼直覺的解決問題,總覺得委派代碼實在麻煩。如果你運作的環境 是 .net framework 3.5(含以上),又覺得委派的代碼總是惹人厭的話,下面的代碼或許幫得上你解決惱人的委派問題,至少幫了我很多,分 享給大家,以下是實例。

首先定義一個類別,來當然是 Control Class 擴充方法類別。

public static class ExtensionControl

{                                               

    public static object GetPropertySafe(this Control control, string propertyName)

    {

        object returnValue = null;

        Action func = () =>

        {

            Type type = control.GetType();

            returnValue = type.InvokeMember(propertyName, BindingFlags.GetProperty, null, control, null);

        };

        if (control.InvokeRequired)

        {

            control.Invoke(func);

        }

        else

        {

            func();

        }

        return returnValue;

    }



    public static object SetPropertySafe(this Control control, string propertyName, object value)

    {

        object returnValue = null;

        Action func = () =>

        {

            Type type = control.GetType();

            returnValue = type.InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { value });

        };

        if (control.InvokeRequired)

        {

            control.Invoke(func);

        }

        else

        {

            func();

        }

        return returnValue;

    }



    public static object GetPropertySafe(this ToolStripMenuItem control, string propertyName)

    {

        object returnValue = null;

        Control owner = control.Owner;

        Action func = () =>

        {

            Type type = control.GetType();

            returnValue = type.InvokeMember(propertyName, BindingFlags.GetProperty, null, control, null);

        };

        if (owner.InvokeRequired)

        {

            owner.Invoke(func);

        }

        else

        {

            func();

        }

        return returnValue;

    }



    public static object SetPropertySafe(this ToolStripMenuItem control, string propertyName, object value)

    {

        object returnValue = null;

        Control owner = control.Owner;

        Action func = () =>

        {

            Type type = control.GetType();

            returnValue = type.InvokeMember(propertyName, BindingFlags.SetProperty, null, control, new object[] { value });                

        };

        if (owner.InvokeRequired)

        {

            owner.Invoke(func);

        }

        else

        {

            func();

        }

        return returnValue;

    }        



    public static object InvokeMethodSafe(this Control control, string methodName, params object[] args)

    {

        object returnValue = null;

        if (args == null)

        {

            args = new object[1];

            args[0] = null;

        }

        else if (args != null && args.Length == 0)

        {

            args = null;

        }

        Action func = () =>

        {

            Type type = control.GetType();                

            returnValue = type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, control, args);

        };

        if (control.InvokeRequired)

        {

            control.Invoke(func);

        }

        else

        {

            func();

        }

        return returnValue;

    }



    public static object InvokeMethodSafe(this ToolStripMenuItem control, string methodName, params object[] args)

    {

        object returnValue = null;

        if (args == null)

        {

            args = new object[1];

            args[0] = null;

        }

        else if (args != null && args.Length == 0)

        {

            args = null;

        }

        Control owner = control.Owner;

        Action func = () =>

        {

            Type type = control.GetType();

            returnValue = type.InvokeMember(methodName, BindingFlags.InvokeMethod, null, control, args);

        };

        if (owner.InvokeRequired)

        {

            owner.Invoke(func);

        }

        else

        {

            func();

        }

        return returnValue;

    }

}    

類別中分別定義 SetPropertySafe, GetPropertySafe, InvokeMethodSafe 方法,當作 是 Control 的擴充方法,在一個 WindowsFormsApplication 加入該代碼或者自己做成 dll 引用都可以,以下是多線程 實作委派的示例。

namespace WindowsFormsApplication1

{

    public partial class MainForm : Form

    {        

        public MainForm()

        {

            InitializeComponent();

        }

 

        private void button1_Click(object sender, EventArgs e)

        {

            Thread thread = new Thread(

                ThreadStart =>

                {

                    //this.textBox1.Text = "Thread Edit";

                    //將上方會產生 InvalidOperationException 的代碼註解,改以下方代碼                    

                    this.textBox1.SetPropertySafe("Text", "ThreadEdit");

                }

            );

            thread.IsBackground = true;

            thread.Start();

        }

    }

}

這樣就徹底解決多線程存取主線程控制項委派的麻煩代碼,同樣一行程式碼做相同的事,接著就可以舉一反三再擴充 Control 方法,技術上並沒有多深,只是一個比較方便的代碼,希望能夠讓一些人在實作多線程委派時,能夠少走彎路,一同為程式加油。

 

你可能感兴趣的:(转)