c# winform编程之多线程ui界面资源修改总结篇

单线程的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/zhangchenliang/archive/2012/03/15/2397984.html

c# winform编程之多线程ui界面资源修改总结篇【转】的更多相关文章

  1. c# winform编程之多线程ui界面资源修改总结篇

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

  2. C# winform编程中多线程操作控件方法

    private void Form1_Load(object sender, EventArgs e) { Thread newthread = new Thread(new ThreadStart( ...

  3. Android异步处理二:使用AsyncTask异步更新UI界面

    在<Android异步处理一:使用Thread+Handler实现非UI线程更新UI界面>中,我们使用Thread+Handler的方式实现了异步更新UI界面,这一篇中,我们介绍一种更为简 ...

  4. Ligg.EasyWinApp-100-Ligg.EasyWinForm:一款Winform应用编程框架和UI库介绍

        本项目是一个Winform应用编程框架和UI库.通过这个该框架,不需任何代码,通过XML配置文件,搭建任意复杂的Windows应用界面,以类似Execel公式的方式实现基本的过程控制(赋值.条 ...

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

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

  6. C#-WinForm跨线程修改UI界面

    待解决的问题 在我做WinForm开发的过程中,经常会遇到耗时操作或阻塞操作.他们会引发软件的卡顿甚至假死,严重影响软件的使用. 因此,这类耗时或阻塞的操作一般都会使用异步的方式去执行,不影响主线程( ...

  7. 转载:21个免费的UI界面设计工具、资源及网站

    我们刚刚介绍了移动设计初探:触屏网页设计.本文将介绍一些UI界面与设计使用的元素.软件和网站.内容很丰富,适合用户体验设计师.界面设计师.产品设计师.JS前段开发.手机产品设计以及iPad和平板电脑产 ...

  8. Winform非UI线程更新UI界面的各种方法小结

    我们知道只有UI线程才能更新UI界面,其他线程访问UI控件被认为是非法的.但是我们在进行异步操作时,经常需要将异步执行的进度报告给用户,让用户知道任务的进度,不至于让用户误认为程序“死掉了”,特别是对 ...

  9. 【转】21个免费的UI界面设计工具、资源及网站

    本文将介绍21个免费的UI界面设计工具.资源及网站,如果你在做用户体验设计.界面设计.产品设计.JS前段开发.手机产品设计以及iPad和平板电脑产品设计,不妨来看看. AD: 2013云计算架构师峰会 ...

随机推荐

  1. Extjs设置或获取cookie

    设置cookie var myCookie = Ext.util.Cookie.set(‘YourCookieName’,'YourValue’); 读取cookie Ext.util.Cookie. ...

  2. 海康威视 - 萤石云开放平台 js 版

    开放平台 https://open.ys7.com/mobile/download.html API http://open.ys7.com/doc/zh/uikit/uikit_javascript ...

  3. JAVAEE——Lucene基础:什么是全文检索、Lucene实现全文检索的流程、配置开发环境、索引库创建与管理

    1. 学习计划 第一天:Lucene的基础知识 1.案例分析:什么是全文检索,如何实现全文检索 2.Lucene实现全文检索的流程 a) 创建索引 b) 查询索引 3.配置开发环境 4.创建索引库 5 ...

  4. iOS 9应用开发教程之使用代码添加按钮美化按钮

    iOS 9应用开发教程之使用代码添加按钮美化按钮 丰富的用户界面 在iOS9中提供了很多的控件以及视图来丰富用户界面,对于这些视图以及控件我们在上一章中做了简单的介绍.本章我们将详细讲解这些视图. i ...

  5. springBoot 自动配置原理

    在之前文章中说过,springBoot会根据jar包去添加许多的自动配置,本文就来说说为什么会自动配置,自动配置的原理时什么? springBoot在运行SpringApplication对象实例化时 ...

  6. php 简单计算权重的方法(适合抽奖类的应用)

    //简单权重计算器 $data222=array(     0=>array('id'=>1,'name'=>'一等奖','weight'=>'3'),     1=>a ...

  7. MyBatis 插入时返回刚插入记录的主键值

    MyBatis 插入时返回刚插入记录的主键值 一.要求: 1.数据库表中的主键是自增长的,如:id: 2.获取刚刚插入的记录的id值: 二.源代码: 1.User.java package cn.co ...

  8. PHP 大神的十大优良习惯

    1.多阅读手册和源代码 没什么比阅读手册更值得强调的事了–仅仅通过阅读手册你就可以学习到很多东西,特别是很多有关于字符串和数组的函数.就在这些函数里面包括许多有用 的功能,如果你仔细阅读手册,你会经常 ...

  9. 构造Huffman以及实现

    构造Huffman 题目 在作业本上分别针对权值集合W=(6,5,3,4,60,18,77)和W=(7,2,4,5,8)构造哈夫曼树,提交构造过程的照片 错误回答 错误原因:遵循左边小于根右边大于根的 ...

  10. hdu 5317 RGCDQ (2015多校第三场第2题)素数打表+前缀和相减求后缀(DP)

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5317 题意:F(x) 表示x的不同质因子的个数结果是求L,R区间中最大的gcd( F(i) , F(j ...