Winform 程序中如何跨线程修改控件的值

翻译|其它|编辑:郝浩|2007-08-10 09:04:48.000|阅读 2502 次

概述:

# 界面/图表报表/文档/IDE等千款热门软控件火热销售中 >>

winform  程序是单线程的。

        /// <summary>
        /// 应用程序入口
        /// </summary>
        [STAThread]
       
static void Main()

    而且对某一个控件来说,只有创建该控件的线程才能修改它的值。比如我们在设计器中拖到窗体上的控件,它们由程序的主线程创建,那么如果我们在执行中又创建了另外一个线程,那么我们在这个新创建的线程中无法直接修改窗体上控件的值。

 

 

    有时候我们的 winform 程序在某一个处理上可能要会费大量的时间,这个时候我们可能会想用另一个线程来处理这个长时间的任务,而同时我 们可以做一些其它的事情。.net 里面多线程异步处理可以使用 ThreadPool.QueueUserWorkItem BackgoundWorder 等就可以非常简单地实现。就像上面图中显示的那样,在点击了按钮之后,我们希望异步地执行按钮的处理程序:

private void btnDoSomething_Click(object sender, EventArgs e)
{
   
WaitCallback callBack = new WaitCallback(DoSomething);
   
ThreadPool.QueueUserWorkItem(callBack, null);
}
private void DoSomething(object state)
{
   
for (int i = 0; i < 100; i++)
    {
       
Thread.Sleep(1000);
    }
}

    这里用 Thread.Sleep(1000)来模拟了一个长时间的任务。到这里异步的目的已经达到,但是我们希望处理的同时能报告处理的进度,好给用户一些提示。比如例子中我们要更新一个进度条,可能会用如下的代码:

    for (int i = 0; i < 100; i++)
    {
       
Thread.Sleep(1000);
       
//can't do the cross-thread updating
        reportProgress(i, 100);
    }
        private void ReportProgress(int countFinished, int total)
        {
            progressBar1.Maximum = total;
            progressBar1.Value = countFinished;
        }

    我们希望可以在异步执行的线程中修改进度条控件的值,但是事与愿违。如果运行这段程序,.net会告诉我们只有创建该控件的线程才可以修改该控件的值 这是线程的安全问题。但是我们确实是需要更新进度条的值怎么办呢?我们不能跨线程直接修改控件的值,但是我们可以通知控件的创建线程我们需要对某个控件进 行修改,让控件的创建线程去帮我们更新控件。“Control.Invokedelegateparas object[]可以帮我们完成这一任务。

private void btnDoSomething_Click(object sender, EventArgs e)
{
   
WaitCallback callBack = new WaitCallback(DoSomething);
   
Object progressBar = progressBar1;
   
ThreadPool.QueueUserWorkItem(callBack, progressBar);
}
private void DoSomething(object state)
{
   
for (int i = 0; i < 100; i++)
    {
       
Thread.Sleep(1000);
       
//can't do the cross-thread updating
        //reportProgress(i, 100);
        ProgressBar pbar = state as ProgressBar;
       
if(pbar!=null)            
            pbar.Invoke(reportProgress, new object[] { i, 100 });
    }
}

    我们调用了 ProgressBar Invoke 方法通知该控件的创建线程修改它的值。Invoke 方法有两个重载的版本:

       public object Invoke(Delegate method);
      
public object Invoke(Delegate method, params object[] args);

    这里使用了第二个,因为我们报告进度的方法需要参数。

       public delegate void ReportTest(int countFinished, int total);
        public FormTest()
        {
            InitializeComponent();
            reportProgress = new ReportTest(ReportProgress);
            // also can add
            //reportProgress += new ReportTest(ReportProgress);
        }

标签:

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

文章转载自:csdn

为你推荐

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


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP