• 多線程委派 转 武胜


    一般我們在實作多線程存取主線程控制項屬性時,必須以委派方式來存取,否則就有可能會出現 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 方法,技術上並沒有多深,只是一個比較方便的代碼,希望能夠讓一些人在實作多線程委派時,能夠少走彎路,一同為程式加油。

     
  • 相关阅读:
    生命
    历史的分岔-中日产业发展史的对照和思考
    挑战自已
    丰台往事已成风,上下求索永不停
    VC6.0实现鼠标光标形状及大小的定制
    RelativeLayout
    16进制颜色代码
    html里的option错误
    Android用户界面设计:布局基础
    Activity详细介绍【官网】
  • 原文地址:https://www.cnblogs.com/zeroone/p/3044210.html
Copyright © 2020-2023  润新知