zoukankan      html  css  js  c++  java
  • Winfrom 如何安全简单的跨线程更新控件

    来源:http://www.cnblogs.com/rainbowzc/archive/2010/09/29/1838788.html

    由于多线程可能导致对控件访问的不一致,导致出现问题。C#中默认是要线程安全的,即在访问控件时需要首先判断是否跨线程,如果是跨线程的直接访问,在运行时会抛出异常。

    解决办法有两个:

    1、不进行线程安全的检查

    2、通过委托的方式,在控件的线程上执行

    常用写法:(不安全)

     private void WriteToolStripMsg(string msg, Color color)
            {
                if (this.InvokeRequired)
                {
                    this.BeginInvoke(new MethodInvoker(delegate()
                    {
                        toolStripMsg.Text = msg;
                        toolStripMsg.ForeColor = color;
    
                    }));
                }
                else
                {
                    toolStripMsg.Text = msg;
                    toolStripMsg.ForeColor = color;
                }
            }
    
    private void btnLogin_Click(object sender, EventArgs e)
            {
    
                string userName = this.txtUserName.Text.Trim();
                string pwd = this.txtPwd.Text.Trim();
    
                if (userName.IsNullOrEmpty())
                {
                    WriteToolStripMsg("请输入登录名...", Color.Red);
                    this.txtUserName.Focus();
                    return;
                }
                if (pwd.IsNullOrEmpty())
                {
                    WriteToolStripMsg("请输入密码...", Color.Red);
                    this.txtPwd.Focus();
                    return;
                }
    
                if (userName.IsNotEmpty() && pwd.IsNotEmpty())
                {
                    WriteToolStripMsg("系统正在登陆中...", Color.Blue);
                    this.btnLogin.BtnEnabled = false;
                    string msg = string.Empty;
                    Thread t = new Thread(() =>
                    {
                        //判断用户登录是否成功。
                        string restulMsg = string.Empty;
                        restulMsg = DataCenterService.Instance.Login(userName, pwd);
                        if (restulMsg.IsNullOrEmpty())
                        {
                            SysUser.CurrUserEntity = DataCenterService.Instance.GetInfoForName(userName);
                            this.DialogResult = DialogResult.OK;
                        }
                        else
                        {
                            WriteToolStripMsg(restulMsg, Color.Red);
                            this.BeginInvoke(new MethodInvoker(delegate()
                            {
                                this.btnLogin.BtnEnabled = true;
                            }));
                        }
                    });
                    t.IsBackground = true;
                    t.Start();
                }
            }
    

      

    上述写法并不是最安全的,存在一定的问题。

    推荐写法:

            delegate void UpdateShowInfoDelegate(System.Windows.Forms.TextBox txtInfo, string Info);
    
            /// <summary>
            /// 显示信息
            /// </summary>
            /// <param name="txtInfo"></param>
            /// <param name="Info"></param>
            public void ShowInfo(System.Windows.Forms.TextBox txtInfo, string Info)
            {
                if (this.InvokeRequired)
                {
                    //this.BeginInvoke(new MethodInvoker(delegate()
                    //{
                    //    txtInfo.AppendText(Info);
                    //    txtInfo.AppendText(Environment.NewLine + "
    ");
                    //    txtInfo.ScrollToCaret();
                    //}));
                    Invoke(new UpdateShowInfoDelegate(ShowInfo), txtInfo,Info);
                    return;
                }
                else
                {
                    txtInfo.AppendText(Info);
                    txtInfo.AppendText(Environment.NewLine + "
    ");
                    txtInfo.ScrollToCaret();
                }
            }
    

    How to update the GUI from another thread in C#?  

    本文转载:http://stackoverflow.com/questions/661561/how-to-update-the-gui-from-another-thread-in-c


    跨线程时使用静态扩展方法更新控件

    在CodeProject上看一个跨线程更新的方法,备忘一下。 
    如果在应用中存在较多简单的跨线程操作,下面的方法可能比较实用:

    public static class ExtensionMethod
    {
        /// <summary>
        /// 有返回值的扩展方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <typeparam name="TResult"></typeparam>
        /// <param name="isi"></param>
        /// <param name="call"></param>
        /// <returns></returns>
        public static TResult SafeInvoke<T, TResult>(this T isi, Func<T, TResult> call) where T : ISynchronizeInvoke
        {
            if (isi.InvokeRequired) { 
                IAsyncResult result = isi.BeginInvoke(call, new object[] { isi }); 
                object endResult = isi.EndInvoke(result); return (TResult)endResult; 
            }
            else
                return call(isi);
        }
        /// <summary>
        /// 没有返回值的扩展方法
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="isi"></param>
        /// <param name="call"></param>
        public static void SafeInvoke<T>(this T isi, Action<T> call) where T : ISynchronizeInvoke
        {
            if (isi.InvokeRequired) isi.BeginInvoke(call, new object[] { isi });
            else
                call(isi);
        }
    }
    

    然后在使用时就可以使用匿名委托很方便的操作:

    lblProcent.SafeInvoke(d => d.Text = textForLabel);
    progressBar1.SafeInvoke(d => d.Value = i);
    string labelText = lblProcent.SafeInvoke(d => d.Text);

    静态的扩展类方法使用泛型模板扩展像所有可继承 ISynchronizeInvoke 接口的控件,几乎适用于常见的所有控件呦 (来自 CodeProject 为所有类型的更新创建异步委托

    原始地址:http://www.codeproject.com/Articles/52752/Updating-Your-Form-from-Another-Thread-without-Cre

    也可以参考:http://www.codeproject.com/Articles/37413/A-Generic-Method-for-Cross-thread-Winforms-Access#xx3867544xx

  • 相关阅读:
    内存分配问题
    C++ assert 的一点说明
    强大的stringstream
    C++中随机数
    C++ 中new
    C++ 中string 详解 转载自 博客园
    未命名名字空间
    使用ifstream和getline读取文件内容[c++]
    6.bootstrap练习笔记-缩略图和list-group
    3.bootstrap练习笔记-媒体内容
  • 原文地址:https://www.cnblogs.com/51net/p/3907863.html
Copyright © 2011-2022 走看看