zoukankan      html  css  js  c++  java
  • WinForm/Silverlight多线程编程中如何更新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 { setget; }
            
    public object parm { setget; }
        }
    }

    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(); });            
            }
        }
    }
  • 相关阅读:
    CodeForces 288A Polo the Penguin and Strings (水题)
    CodeForces 289B Polo the Penguin and Matrix (数学,中位数)
    CodeForces 289A Polo the Penguin and Segments (水题)
    CodeForces 540C Ice Cave (BFS)
    网站后台模板
    雅图CAD
    mbps
    WCF学习-协议绑定
    数据库建表经验总结
    资源位置
  • 原文地址:https://www.cnblogs.com/jordan2009/p/2032957.html
Copyright © 2011-2022 走看看