单线程的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
分享到:
相关推荐
5.8 MemoryStream 简单示例 : XmlWriter中使用MemoryStream 5.9 MemoryStream 简单示例 :自定义一个处理图片的HttpHandler 6.1 简单介绍一下BufferedStream 6.2 如何理解缓冲区? 6.3 BufferedStream的优势 6.4 从...
dos系统概述及详解 DOS系统简介 dos系统是典型的什么系统 DOS基本概念 dos百度百科 dos系统使用 dos常用命令 dos系统基本命令
NULL 博文链接:https://wellfrog.iteye.com/blog/1133725
javase集合 温故而知新.doc
CPU 技术温故而知新.pdf
CPU 技术温故而知新(之三).pdf
食品饮料行业深度报告:温故而知新,关注本轮大众品提价与盈利传导(2022)(23页).pdf
Android系统从5.0开始引进了许多新的控件,它们给予了用户更好的体验,这些控件都遵循现在流行的Material Design设计原则。今天我们就来温故一下SnackBar控件,它是一种类似Android Toast(显示提示信息) 与 对话框...
知道有没有人很长不是不复习基础或者一些编程思想,会忘记,博主呢秉承着温故而知新的道理把基础从到位复习了一边,其中还包括一些算法指针,统计目录,字符串,数组的方法,mvc思想,匿名函数,引用等,代码可以...
本书浅显易懂的介绍了JAVA线程相关的设计模式,通过程序范例和UML图示来一一解说,书中代码的重要...最后附上练习问题,让读者可以温故而知新,能快速地吸收书中的精华,书中最后附上练习问题解答,方便读者学习验证。
多线程与并发处理是程序设计好坏优劣的重要课题,本书通过浅显易懂的文字与实例来介绍JAVA线程相关...最后附上练习问题,让读者可以温故而知新,能快速地吸收书中的精华,书中最后附上练习问题解答,方便读者学习验证。
很基础的电子基础东西,相信很多朋友是不需要的,不过还是放上去,有需要回顾一下的~~~~~~~ 请看这里!
最后附上练习问题,让读者可以温故而知新,能快速地吸收书中的精华,书中最后附上练习问题解答,方便读者学习验证。 目录 漫谈UML UML 类图 类和层次结构的关系 接口与实现 聚合 访问控制 类间的关联性 顺序图 处理...
java多线程同步互斥访问实例,对于初学者或是温故而知新的同道中人都是一个很好的学习资料
一些ppt文件,少而精,适合复习和回顾,温故而知新:)
温故而知新,我们来简单回顾一下上篇的内容,上一篇我们分析了SpringBoot启动时广播生命周期事件的原理,现将关键步骤再浓缩总结下: 为广播SpringBoot内置生命周期事件做前期准备:1)首先加载ApplicationListener...
《JAVA多线程设计模式》中包含JAVA线程的介绍导读,12个重要的线程设计模式和全书总结以及丰富的...最后附上练习问题,让读者可以温故而知新,能快速地吸收书中的精华,书中最后附上练习问题解答,方便读者学习验证。
多线程与并发处理是程序设计好坏优劣的重要课题,本书通过浅显易懂的文字与实例来介绍JAVA线程...最后附上练习问题,让读者可以温故而知新,能快速地吸收书中的精华,书中最后附上练习问题解答,方便读者学习验证。
多线程与并发处理是程序设计好坏优劣的重要课题,本书通过浅显易懂的文字与实例来介绍JAVA线程...最后附上练习问题,让读者可以温故而知新,能快速地吸收书中的精华,书中最后附上练习问题解答,方便读者学习验证。