博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
WinForm/Silverlight多线程编程中如何更新UI控件的值
阅读量:5059 次
发布时间:2019-06-12

本文共 4279 字,大约阅读时间需要 14 分钟。

单线程的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(); });            
        }
    }
}

转载于:https://www.cnblogs.com/youlechang123/archive/2011/11/05/2236813.html

你可能感兴趣的文章
有标号DAG计数 [容斥原理 子集反演 组合数学 fft]
查看>>
Recipe 1.4. Reversing a String by Words or Characters
查看>>
Rule 1: Make Fewer HTTP Requests(Chapter 1 of High performance Web Sites)
查看>>
sql注入
查看>>
「破解」Xposed强
查看>>
Linux 平台下 MySQL 5.5 安装 说明 与 示例
查看>>
src与href的区别
查看>>
ABAP工作区,内表,标题行的定义和区别
查看>>
《xxx重大需求征集系统的》可用性和可修改性战术分析
查看>>
Python 中 创建类方法为什么要加self
查看>>
关于indexOf的使用
查看>>
【转】JS生成 UUID的四种方法
查看>>
英语单词
查看>>
centos6.8下安装matlab2009(图片转帖)
查看>>
Mongo自动备份
查看>>
求助大神!怎样批量删除数据库表中某个字段中同样的一段字符!
查看>>
VMWARE虚拟机无法访问的三种方法分析
查看>>
enq: SQ - contention
查看>>
cer证书签名验证
查看>>
ant 安装
查看>>