访问UI界面控件

 

多任务的处理有两种不同的类型:基于进程和基于线程。理解这两者间的区别很重要。一个进程(process)本质上一个正在运行的程序。因此,基于进程的多任务处理(process-based multitasking)允许计算机同时运行两个或多个程序。例如,在我们使用电子表格或浏览Internet的同时,还可以运行字处理程序,听听喜欢的音乐等等。因此,基于进程的多任务处理中,程序是调度程序能够调度的最小单元。

线程(thread)则是一个可执行代码的调度单元,它的名称来源于概念“执行的线程化”。在基于线程的多任务处理环境中,所有进程都至少有一个线程,而且可以有更多。这意味着一个程序能够一次执行两个或多个操作,例如,一个文本编辑器可以在打印的同时格式化文本,只要这两个动作能由两个独立的线程执行即可。

基于进程的多任务处理和基于进程的多任务处理之间的不同归纳如下:基于进程的多任务是处理并发执行的程序,而基于线程的多任务处理则是处理同一个程序中并发执行的不同程序段。

多线程的主要优点是它使人们能够编写高效的程序,可能大家知道,大多数I/O设备,不管是网络接口、磁盘驱动器、还是键盘,其运行速度都比CPU速度慢的多。因此程序往往需要花费大量的时间来等待发送(接收)I/O设备上的信息。通过使用多线程,程序能够在它的空闲时间执行另一个任务。提高了CPU的使用效率。

.NET中用户界面线程是独立的,如果有两个或多个线程操作某一控件的状态则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用情况和死锁。确保以线程安全方式访问控件非常重要。

.NET Framework 有助于在以非线程安全方式访问控件时检测到这一问题。在调试器中运行应用程序时,如果创建某控件的线程之外的其他线程试图调用该控件,则调试器会引发一个 InvalidOperationException,并提示消息:“从不是创建控件 control name 的线程访问它。”

此异常在调试期间和运行时的某些情况下可靠地发生。强烈建议您在显示此错误信息时修复此问题。在调试以 .NET Framework 2.0 版之前的 .NET Framework 编写的应用程序时,可能会出现此异常。从VS2003过度到VS2005中的程序我们需要加入一句代码才可运行:

System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
下面是我们常用的方式:

1.       查询控件的 InvokeRequired 属性。

2.       如果 InvokeRequired 返回 true,则使用实际调用控件的委托来调用 Invoke。

3.       如果 InvokeRequired 返回 false,则直接调用控件。

在下面的代码示例中,此逻辑是在一个称为 SetText 的实用工具方法中实现的。名为 SetTextDelegate 的委托类型封装 SetText 方法。TextBox 控件的 InvokeRequired 返回 true 时,SetText 方法创建 SetTextDelegate 的一个实例,并调用窗体的 Invoke 方法。这使得 SetText 方法被创建 TextBox 控件的线程调用,而且在此线程上下文中将直接设置 Text 属性。

public partial class Form1 : Form

    {

        public Form1()

        {

            InitializeComponent();

        }

        delegate void SetTextCallback(string text);

        private Thread demoThread = null;

        private void btnRun_Click(object sender, EventArgs e)

        {

            this.demoThread =

        new Thread(new ThreadStart(this.ThreadProcUnsafe));

            this.demoThread.Start();

               }

         private void SetText(string text)

        {

               if (this.textBox1.InvokeRequired) //该属性通过线程的ID比较了创建控件线程和调用控件的线程是否是同一线程,不是同一线程则为ture

            {

                SetTextCallback d = new SetTextCallback(SetText);

                this.Invoke(d, new object[] { text }); //将修改控件属性的方法交给创建控件线程来完成

            }

            else

            {

                this.textBox1.Text = text;

            }

         }

        private void ThreadProcUnsafe()

        {

            for (int i = 0; i < 10; i++)

            {

                this.SetText(i.ToString());

                Thread.Sleep(200);

            }

        

        }

     }

 通过以上方式,我们可以很轻松的访问UI界面的控件了

posted @ 2008-08-13 16:56  kewin  阅读(592)  评论(2编辑  收藏  举报