winform程序中如何跨线程修改控件的值
2007-08-09 20:51
495 查看
winform程序是单线程的。
而且对某一个控件来说,只有创建该控件的线程才能修改它的值。比如我们在设计器中拖到窗体上的控件,它们由程序的主线程创建,那么如果我们在执行中又创建了另外一个线程,那么我们在这个新创建的线程中无法直接修改窗体上控件的值。
有时候我们的winform程序在某一个处理上可能要会费大量的时间,这个时候我们可能会想用另一个线程来处理这个长时间的任务,而同时我 们可以做一些其它的事情。.net里面多线程异步处理可以使用ThreadPool.QueueUserWorkItem, BackgoundWorder等就可以非常简单地实现。就像上面图中显示的那样,在点击了按钮之后,我们希望异步地执行按钮的处理程序:
这里用Thread.Sleep(1000)来模拟了一个长时间的任务。到这里异步的目的已经达到,但是我们希望处理的同时能报告处理的进度,好给用户一些提示。比如例子中我们要更新一个进度条,可能会用如下的代码:
我们希望可以在异步执行的线程中修改进度条控件的值,但是事与愿违。如果运行这段程序,.net会告诉我们“只有创建该控件的线程才可以修改该控件的值”, 这是线程的安全问题。但是我们确实是需要更新进度条的值怎么办呢?我们不能跨线程直接修改控件的值,但是我们可以通知控件的创建线程我们需要对某个控件进 行修改,让控件的创建线程去帮我们更新控件。“Control.Invoke(delegate,paras object[])”可以帮我们完成这一任务。
我们调用了ProgressBar的Invoke方法通知该控件的创建线程修改它的值。Invoke方法有两个重载的版本:
这里使用了第二个,因为我们报告进度的方法需要参数。
/// <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.Invoke(delegate,paras 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); }
相关文章推荐
- 如何获得其他程序的EDIT控件中的内容并修改
- 如何用C#写一个透明控件?(WinForm程序)
- 如何修改C# winform程序图标
- 为什么Winform不允许跨线程修改UI线程控件的值?
- 如何在程序中修改控件的字体
- WPF / Win Form:多线程去修改或访问UI线程数据的方法( winform 跨线程访问UI控件 )
- WinForm------如何修改PanelControl控件背景色
- WinForm程序如何等待多个线程执行完后提示用户?
- winform 入门开发,VS 程序自带的日历控件日期显示格式是xxxx年x月x日,如何改成xxxx-xx-xx 的格式 ?
- [导入]WinForm程序如何等待多个线程执行完后提示用户?
- 如何在C# WinForm 程序中使用WebBrowser控件时设置COOKIE的值。
- WinForm程序如何等待多个线程执行完后提示用户?
- [VB.NET]如何在DataGridView控件中增加、删除和修改记录(用程序代码的方法)
- 如何用C#写一个透明控件?(WinForm程序)
- Winform 线程中修改控件属性.时钟示例
- c#winform中如何修改ListView控件每个单元格的颜色
- C#如何使用BackgroundWork后台辅助线程控件
- c# winform 工作线程访问修改界面线程
- 如何修改线程的Access Token
- 如何提高程序的可修改性