温故而知新:WinForm/Silverlight多线程编程中如何更新UI控件的值

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

单线程的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

目录
相关文章
|
1月前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
|
2月前
|
算法 API C++
【Qt UI】QT 窗口/控件置顶方法详解
【Qt UI】QT 窗口/控件置顶方法详解
73 0
|
2月前
|
算法 前端开发 C++
【Qt UI相关】Qt设置窗体或控件的背景色透明
【Qt UI相关】Qt设置窗体或控件的背景色透明
30 0
|
2月前
|
前端开发 搜索推荐 开发者
SAP UI5 sap.m.Column 控件的 minScreenWidth 属性介绍
SAP UI5 sap.m.Column 控件的 minScreenWidth 属性介绍
32 0
|
1月前
|
XML Java Android开发
Android之UI基础控件
Android之UI基础控件
|
1天前
|
设计模式 消息中间件 安全
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
【Java多线程】关于多线程的一些案例 —— 单例模式中的饿汉模式和懒汉模式以及阻塞队列
8 0
|
1天前
|
Java 数据库
【Java多线程】对线程池的理解并模拟实现线程池
【Java多线程】对线程池的理解并模拟实现线程池
9 1
|
1天前
|
Java
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
【Java多线程】分析线程加锁导致的死锁问题以及解决方案
9 1
|
1天前
|
存储 缓存 安全
【Java多线程】线程安全问题与解决方案
【Java多线程】线程安全问题与解决方案
8 1
|
1天前
|
Java 调度
【Java多线程】线程中几个常见的属性以及状态
【Java多线程】线程中几个常见的属性以及状态
7 0

热门文章

最新文章