单线程的winfom程序中,设置一个控件的值是很easy的事情,直接 this.TextBox1.value = "Hello World!";就搞定了,但是如果在一个新线程中这么做,比如:


private void btnSet_Click(object sender, EventArgs e)
{    
    Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
    //当然也可以用匿名委托写成Thread t = new Thread(SetTextBoxValue);
    t.Start("Hello World");
} void SetTextBoxValue(object obj) 
{
    this.textBox1.Text = obj.ToString();
}

运行时,会报出一个无情的错误:
线程间操作无效: 从不是创建控件“textBox1”的线程访问它。

究其原因,winform中的UI控件不是线程安全的,如果可以随意在任何线程中改变其值,你创建一个线程,我创建一个线程,大家都来抢着更改"TextBox1"的值,没有任何秩序的话,天下大乱...

解决办法:
1.掩耳盗铃法(Control.CheckForIllegalCrossThreadCalls = false;)--仅Winform有效


using System;
using System.Threading;
using System.Windows.Forms; namespace ThreadTest
{
    public partial class Form1 : Form
    {                 public Form1()
        {
            InitializeComponent();
            Control.CheckForIllegalCrossThreadCalls = false;//这一行是关键      
        }
                private void btnSet_Click(object sender, EventArgs e)
        {           
            Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
            t.Start("Hello World");
        }         void SetTextBoxValue(object obj) 
        {
            this.textBox1.Text = obj.ToString();
        }        
    }
}

设置Control.CheckForIllegalCrossThreadCalls为false,相当于不检测线程之间的冲突,允许各路线程随便乱搞,当然最终TextBox1的值到底是啥难以预料,只有天知道,不过这也是最省力的办法

2.利用委托调用--最常见的办法(仅WinForm有效)


using System;
using System.Threading;
using System.Windows.Forms; namespace ThreadTest
{
    public partial class Form1 : Form
    {
        delegate void D(object obj);         public Form1()
        {
            InitializeComponent();            
        }
                private void btnSet_Click(object sender, EventArgs e)
        {           
            Thread t = new Thread(new ParameterizedThreadStart(SetTextBoxValue));
            t.Start("Hello World");
        }         void SetTextBoxValue(object obj) 
        {
            if (textBox1.InvokeRequired)
            {
                D d = new D(DelegateSetValue);
                textBox1.Invoke(d,obj);             }
            else 
            {
                this.textBox1.Text = obj.ToString();
            }
        }         void DelegateSetValue(object obj) 
        {
            this.textBox1.Text = obj.ToString();
        }
    }
}

3.利用SynchronizationContext上下文 -- 最神秘的方法(Winform/Silverlight能用)

之所以说它神秘,是因为msdn官方对它的解释据说也是不清不楚


using System;
using System.Threading;
using System.Windows.Forms; namespace ThreadTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();            
        }                private void btnSet_Click(object sender, EventArgs e)
        {
            Thread t = new Thread(new ParameterizedThreadStart(Run));
            MyPram _p = new MyPram() { context = SynchronizationContext.Current, parm = "Hello World" };
            t.Start(_p);
        }         void Run(object obj) 
        {
            MyPram p = obj as MyPram;
            p.context.Post(SetTextValue, p.parm);
        }         void SetTextValue(object obj) 
        {
            this.textBox1.Text = obj.ToString();
        }
    }     public class MyPram 
    {
        public SynchronizationContext context { set; get; }
        public object parm { set; get; }
    }
}

4.利用BackgroundWorker --最偷懒的办法(Winform/Silverlight通用)

BackgroundWorker会在主线程之外,另开一个后台线程,我们可以把一些处理放在后台线程中处理,完成之后,后台线程会把结果传递给主线程,同时结束自己。


using System;
using System.ComponentModel;
using System.Windows.Forms; namespace ThreadTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();            
        }                private void btnSet_Click(object sender, EventArgs e)
        {
            //MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
            using (BackgroundWorker bw = new BackgroundWorker())
            {
                bw.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bw_RunWorkerCompleted);
                bw.DoWork += new DoWorkEventHandler(bw_DoWork);
                bw.RunWorkerAsync("Hello World");
            }
        }         void bw_DoWork(object sender, DoWorkEventArgs e)
        {
            //MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
            e.Result = e.Argument;//这里只是简单的把参数当做结果返回,当然您也可以在这里做复杂的处理后,再返回自己想要的结果(这里的操作是在另一个线程上完成的)
        }         void bw_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            //这时后台线程已经完成,并返回了主线程,所以可以直接使用UI控件了
            this.textBox1.Text = e.Result.ToString();
            //MessageBox.Show(Thread.CurrentThread.ManagedThreadId.ToString());
        }       
    }    
}

5.Dispatcher.BeginInvoke--Silverlight的独门秘籍


代码

using System.Threading;
using System.Windows.Controls;
using System.Windows.Input; namespace ThreadTest
{
    public partial class MainPage : UserControl
    {
        public MainPage()
        {
            InitializeComponent();
        }         private void LayoutRoot_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            Thread t = new Thread(SetTextValue);
            t.Start("Hello World");
        }         void SetTextValue(object text) 
        {
            this.Dispatcher.BeginInvoke(() => { this.txt.Text = text.ToString(); });            
        }
    }
}
 
转自菩提树下的杨过http://www.cnblogs.com/yjmyzz/archive/2009/11/25/1610253.html

WinForm/Silverlight多线程编程中如何更新UI控件的值的更多相关文章

  1. (转).NET 4.5中使用Task.Run和Parallel.For()实现的C# Winform多线程任务及跨线程更新UI控件综合实例

    http://2sharings.com/2014/net-4-5-task-run-parallel-for-winform-cross-multiple-threads-update-ui-dem ...

  2. 富客户端 wpf, Winform 多线程更新UI控件

    前言 在富客户端的app中,如果在主线程中运行一些长时间的任务,那么应用程序的UI就不能正常相应.因为主线程要负责消息循环,相应鼠标等事件还有展现UI. 因此我们可以开启一个线程来格外处理需要长时间的 ...

  3. C# Winform 跨线程更新UI控件常用方法汇总(多线程访问UI控件)

    概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件的线程访问它”的异常.处理跨线程更新Winform UI控件常用的方法有4种:1. ...

  4. C# Winform 跨线程更新UI控件常用方法总结(转)

    出处:http://www.tuicool.com/articles/FNzURb 概述 C#Winform编程中,跨线程直接更新UI控件的做法是不正确的,会时常出现“线程间操作无效: 从不是创建控件 ...

  5. C#子线程更新UI控件的方法总结

    http://blog.csdn.net/jqncc/article/details/16342121 在winform C/S程序中经常会在子线程中更新控件的情况,桌面程序UI线程是主线程,当试图从 ...

  6. C# 后台线程更新UI控件

    /********************************************************************************* * C# 后台线程更新UI控件 * ...

  7. winform中更新UI控件的方案介绍

    这是一个古老的话题...直入主题吧! 对winfrom的控件来说,多线程操作非常容易导致复杂且严重的bug,比如不同线程可能会因场景需要强制设置控件为不同的状态,进而引起并发.加锁.死锁.阻塞等问题. ...

  8. Android中多线程编程(三)Handler更新UI的方式

    Handler更新UI的方式和原因以及遇到的问题 1.方式: 仅仅能通过Handler来更新UI. 代码例如以下: package com.chengdong.su.handlerdemo; impo ...

  9. winform中如何在多线程中更新UI控件--ListView实时显示执行信息

    1.在winform中,所有对UI的操作,都得回到UI线程(主线程)上来,才不会报错 线程间操作无效: 从不是创建控件的线程访问它. 2.在winform中,允许通过Control.invoke对控件 ...

随机推荐

  1. 初学c# -- 学习笔记(一)

    初学c# -- 学习笔记(一) 学习C#了,参考许多资料,一步步学习.这一段学习ajax的工作原理,参照其他例子写了web版的群聊小程序,全部文件代码也就不到300行,很简单.使用时先输入用户名,点确 ...

  2. jquery实现淡入淡出

    fade方法包括四个: (1)fadeIn(speed,callback):淡入的方法,speed代表淡入的速度,可以是slow,fast,毫秒,不填等 例如: $(document).ready(f ...

  3. lucene写索引出现锁文件的原因之一

    lucene正常情况目录下的文件 有三个文件. segments.gen segments_a08, 还有一个类似 _uw.cfs名字的东西. 当然,不一定都一样, 但肯定是这三个. 如果出现了很多文 ...

  4. linux 正则表达式与文件格式化处理

    此文涉及命令:grep.sed.awk.printf.diff.cmp.patch. 概念: 什么是正则表示法 简单的说,正则表示法就是处理字符串的方法,他是以行为单位来进行字符串的处理行为, 正则表 ...

  5. HTML5 ---localStorage储存实例

     <!DOCTYPE html><html> <head> <meta charset="UTF-8"> <title> ...

  6. redis——持久化篇

    众所周知,redis是内存数据库,它把数据存储在内存中,这样在加快读取速度的同时也对数据安全性产生了新的问题,即当redis所在服务器发生宕机后,redis数据库里的所有数据将会全部丢失. 为了解决这 ...

  7. C#获取程序集自动增加的版本号和编译时间

    1. 首先找到文件AssemblyInfo.cs, 路径如下: 2. 修改版本的格式,修改后,程序每次编译,程序集的版本号都会自增. 修改前: [assembly: AssemblyVersion(& ...

  8. JS-小球碰撞反弹

    类似于屏保的一种动画,当小球碰到边框时,发生反弹,并且变化颜色. <!DOCTYPE html><html lang="en"><head>   ...

  9. [刘阳Java]_JVM工作流程_第4讲

    程序员写好一段Java源程序-->编译-->字节码-->JVM-->硬件平台(操作系统)

  10. 利用OpenShift托管Node.js Web服务进行微信公众号开发

    最近写了一个微信的翻译机器人.用户只要关注该公众号,发送英文的消息,就能收到中文翻译的回复.有兴趣的读者可以扫描下面的二维码关注该公众号,尝试发送英文单词试试看.(有时候第一次发送单词会收到“该公众号 ...