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

news/2024/7/5 18:04:56 标签: 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/hobby0524/p/7305019.html


http://www.niftyadmin.cn/n/1665945.html

相关文章

selenium 原理应用 - 利用 requests 模拟 selenium 驱动浏览器

前言 selenium 是一个 Web 自动化测试的开源框架,它支持多语言:python/java/c#… 前面也有一篇文章说明了,selenium 浏览器的环境搭建。 selenium 支持多语言,是因为 selenium 与浏览器驱动之间是通过 http 协议进行通信的。只…

区块链与Git版本工具的比较

区块链与Git版本工具的比较 来源:http://www.jianshu.com/p/b96b98983df6作者: 梁波林 相同点: 1. 分布式存储方案 2. 链式数据 3. 去中心化 4. 支持离线访问 5. 交易量较小 6. 参与方多,网络规模大 不同: 1. 数据内容…

RubyMine 2018.3.5 发布,流行的 Ruby 开发工具

开发四年只会写业务代码,分布式高并发都不会还做程序员? >>> RubyMine 2018.3.5 (build 183.5912.16) 发布了,带来了一些平台上的改进。RubyMine 是一个为 Ruby 和 Rails 开发者准备的 IDE。 新版本的更新亮点有: Ruby…

六个开源软件开发的“潜规则”

你想成为开源项目中得意满满、功成名就的那个人吗,那就要遵守下面的“潜规则”。 正如体育界不成文的规定一样,这些规则基本上不会出现在官方文档和正式记录上。比如说,在棒球运动中,从比分领先时不要盗垒,到跑垒员跑了…

C++进阶篇二:C++标准模版库之算法

为什么80%的码农都做不了架构师&#xff1f;>>> 写在<algorithm>头文件之前 在CSTL的头文件<algorithm>中&#xff0c;各式算法函数往往会对支持该算法的最低迭代级别作出要求。任何算法作用的容器或迭代&#xff0c;只有支持的权限等于或高于算法要求…

cookie 与 SSO 的两三事

前言 前面的文章记录了proxy代理后端接口&#xff0c;其实践过程中也不乏踩坑之处。 SSO单点登录 这里有一篇文章写得不错&#xff0c;分析了淘宝、天猫的登录场景(漫谈单点登录)。 COOKIE 关于cookie的知识自己搜&#xff0c;我这就不废话了。关键看请求的response headers &a…

Katalon Studio 自动化测试工具介绍

前言 在软件测试这条道路上&#xff0c;大部分的职业技能发展道路都会是功能测试-> 自动化测试-> 性能测试-> 安全测试/测试开发。 但是却有着一部分人起初进入软件测试这一行看重的就是软件测试属于 IT 行业&#xff0c;门槛比较低&#xff0c;不需要代码基础。这就…

优秀的产品经理,必须翻越这三座大山

作为一个资深产品经理&#xff0c;这几年工作中遇到的挫折和收获&#xff0c;数也数不清。看到用户数的不断增长和好评我会犹如打了鸡血&#xff0c;听到伙伴的质疑和用户的指责我也会在回家地铁上默默掉眼泪&#xff0c;后悔当初的选择。对于新入行的童鞋&#xff0c;我这个老…