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 + "\r\n");
                //    txtInfo.ScrollToCaret();
                //}));
                Invoke(new UpdateShowInfoDelegate(ShowInfo), txtInfo,Info);
                return;
            }
            else
            {
                txtInfo.AppendText(Info);
                txtInfo.AppendText(Environment.NewLine + "\r\n");
                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

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏恰童鞋骚年

ASP.Net请求处理机制初步探索之旅 - Part 5 ASP.Net MVC请求处理流程

开篇:上一篇我们了解了在WebForm模式下一个Page页面的生命周期,它经历了初始化Init、加载Load以及呈现Render三个重要阶段,其中构造了页面控件...

1393
来自专栏林德熙的博客

WPF 拼音输入法

实际上本文是在使用一个好用的软件 希沃白板 的时候发现在里面很难输入拼音来做课堂活动。

4782
来自专栏大内老A

为ASP.NET MVC创建一个基于Unity的ControllerFactory

谈到IoC和ASP.NET的集成,很多人会先后想到Ninject,不过我们个人还是倾向于Unity。这篇文章简单地介绍如果创建基于Unity的Controlle...

1937
来自专栏NetCore

流畅地HtmlHelper-Asp.Net MVC

今天抛开 Fluent NHibernate 不谈,我们来谈谈 Asp.Net MVC ,在MVC的View中,我们经常会使用HtmlHelper来生成各种ht...

2048
来自专栏debugeeker的专栏

source insight coredump分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuzhina/article/detai...

751
来自专栏AhDung

【C#】分享带等待窗体的任务执行器一枚

-------------20150415原文(已更新)-------------

1423
来自专栏君赏技术博客

HQ移动20170317期周报

删除缓存:rm ~/Library/Caches/CocoaPods/search_index.json

1103
来自专栏GIS讲堂

excel中提取中文拼音

概述:在工作时,有时候会用到汉语拼音,本文讲述如何在Excel中通过vba程序提取汉字的拼音。

1823
来自专栏DOTNET

asp.net web api 下载之断点续传

一、基本思想 利用 HTTP 请求的Range标头值,来向服务端传递请求数据的开始位置和结束位置。服务端获得这两个参数后,将指定范围内的数据传递给客户端。当客户...

47312
来自专栏hbbliyong

WPF备忘录(3)如何从 Datagrid 中获得单元格的内容与 使用值转换器进行绑定数据的转换IValueConverter

一、如何从 Datagrid 中获得单元格的内容    DataGrid 属于一种 ItemsControl, 因此,它有 Items 属性并且用ItemCon...

3737

扫码关注云+社区

领取腾讯云代金券