彩票走势图

WinForm/Silverlight多线程编程中如何更新UI控件的值

转帖|其它|编辑:郝浩|2011-05-03 14:49:24.000|阅读 858 次

概述:本文主要介绍在WinForm/Silverlight多线程编程中如何更新UI控件的值,希望对大家有帮助。

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

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


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn

文章转载自:博客园

为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP