004. 线程间操作无效: 从不是创建控件“textBox1”的线程访问它

最简单的方法(不推荐):

在窗体构造函数中写Control.CheckForIllegalCrossThreadCalls =false;

为什么不推荐上面的方法:

为避免空间造成死锁, .net framework 2.0 之后 拒绝多线程访问空间, 以前Control.CheckForIllegalCrossThreadCalls 默认就是flase, 2.0后默认为true。当然如果能保证程序中不会好几个线程同时操作一个控件用上面的方法也可以, 如果存在多个线程一起操作控件使用下面的方法; 下面是来自微软官网给出的示例:

三种处理方案见源码:

Form1.cs源码:

using System;
  using System.ComponentModel;
  using System.Threading;
  using System.Windows.Forms;

namespace CrossThreadDemo
{
    public partial class Form1 : Form
    {
        //设置这个委托支持异步调用文本框控件的文本属性。
        delegate void SetTextCallback(string text);
        //这个线程用于演示和线程安全的和不安全的方法来调用一个Windows窗体控件。
        private Thread demoThread = null;

        //这个BackgroundWorker用于演示执行异步操作, 推荐使用该方法。
        private BackgroundWorker backgroundWorker1;

        private TextBox textBox1;
        private Button setTextUnsafeBtn;
        private Button setTextSafeBtn;
        private Button setTextBackgroundWorkerBtn;
         
        public Form1()
        {
            InitializeComponent();
        }

        //这个事件处理程序创建一个线程,该线程演示用不安全的方式调用 Windows窗体, 在.net framework2.0后被禁用
        private void setTextUnsafeBtn_Click(object sender,EventArgs e)
        {
            this.demoThread = new Thread(new ThreadStart(this.ThreadProcUnsafe));
            this.demoThread.Start();
        }

     //这个方法执行工作线程, 文本框控件不安全的调用, 一执行就会报错.
        private void ThreadProcUnsafe()
        {
            //线程间操作无效: 从不是创建控件“textBox1”的线程访问它。
            this.textBox1.Text = "This text was set unsafely.";
        }
    //这个事件处理程序创建一个线程,该线程使用安全的方式调用 Windows窗体.
        private void setTextSafeBtn_Click(object sender,EventArgs e)
        {
            this.demoThread = new Thread(new ThreadStart(this.ThreadProcSafe));
            this.demoThread.Start();
        }

        //这个方法执行工作线程,使 文本框控件的线程安全的调用.
        private void ThreadProcSafe()
        {
            this.SetText("This text was set safely.");
        }

        //这个方法演示了线程通过安全的模式, 调用一个Windows窗体控件。如果调用线程和当前创建了文本框控件的线程不用,该方法创建一个SetTextCallback,并使用了异步调用自身调用方法,
    //如果调用线程创建的线程是一样的文本框控件,直接设置文本属性。
private void SetText(string text) { if (this.textBox1.InvokeRequired) { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { //在此设置textBox1的文本 this.textBox1.Text = text; } } //这个事件处理程序通过调用RunWorkerAsync BackgroundWorker。设置文本框控件的文本属性, 用BackgroundWorker提高RunWorkerCompleted事件。 private void setTextBackgroundWorkerBtn_Click(object sender,EventArgs e) { this.backgroundWorker1.RunWorkerAsync(); } //这个事件处理程序设置文本框的文本属性控制。它调用创建的线程文本框控件,所以调用是线程安全的,异步执行BackgroundWorker是首选方法操作. private void backgroundWorker1_RunWorkerCompleted(object sender,RunWorkerCompletedEventArgs e) { this.textBox1.Text ="This text was set safely by BackgroundWorker."; } } }

Program.cs源码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    static class Program
    {
        /// <summary>
        /// 应用程序的主入口点。
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new CrossThreadDemo.Form1());
        }
    }
}

Form1.Designer.cs源码:

namespace CrossThreadDemo
{
    partial class Form1
    {
        /// <summary>
        /// 必需的设计器变量。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary>
        /// 清理所有正在使用的资源。
        /// </summary>
        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region Windows 窗体设计器生成的代码

        /// <summary>
        /// 设计器支持所需的方法 - 不要
        /// 使用代码编辑器修改此方法的内容。
        /// </summary>
        private void InitializeComponent()
        {
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.setTextUnsafeBtn = new System.Windows.Forms.Button();
            this.setTextSafeBtn = new System.Windows.Forms.Button();
            this.setTextBackgroundWorkerBtn = new System.Windows.Forms.Button();
            this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
            this.SuspendLayout();
            // 
            // textBox1
            // 
            this.textBox1.Location = new System.Drawing.Point(12, 12);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(240, 21);
            this.textBox1.TabIndex = 0;
            // 
            // setTextUnsafeBtn
            // 
            this.setTextUnsafeBtn.Location = new System.Drawing.Point(15, 55);
            this.setTextUnsafeBtn.Name = "setTextUnsafeBtn";
            this.setTextUnsafeBtn.Size = new System.Drawing.Size(75, 23);
            this.setTextUnsafeBtn.TabIndex = 1;
            this.setTextUnsafeBtn.Text = "Unsafe Call";
            this.setTextUnsafeBtn.Click += new System.EventHandler(this.setTextUnsafeBtn_Click);
            // 
            // setTextSafeBtn
            // 
            this.setTextSafeBtn.Location = new System.Drawing.Point(96, 55);
            this.setTextSafeBtn.Name = "setTextSafeBtn";
            this.setTextSafeBtn.Size = new System.Drawing.Size(75, 23);
            this.setTextSafeBtn.TabIndex = 2;
            this.setTextSafeBtn.Text = "Safe Call";
            this.setTextSafeBtn.Click += new System.EventHandler(this.setTextSafeBtn_Click);
            // 
            // setTextBackgroundWorkerBtn
            // 
            this.setTextBackgroundWorkerBtn.Location = new System.Drawing.Point(177, 55);
            this.setTextBackgroundWorkerBtn.Name = "setTextBackgroundWorkerBtn";
            this.setTextBackgroundWorkerBtn.Size = new System.Drawing.Size(75, 23);
            this.setTextBackgroundWorkerBtn.TabIndex = 3;
            this.setTextBackgroundWorkerBtn.Text = "Safe BW Call";
            this.setTextBackgroundWorkerBtn.Click += new System.EventHandler(this.setTextBackgroundWorkerBtn_Click);
            // 
            // backgroundWorker1
            // 
            this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
            // 
            // Form1
            // 
            this.ClientSize = new System.Drawing.Size(268, 96);
            this.Controls.Add(this.setTextBackgroundWorkerBtn);
            this.Controls.Add(this.setTextSafeBtn);
            this.Controls.Add(this.setTextUnsafeBtn);
            this.Controls.Add(this.textBox1);
            this.Name = "Form1";
            this.Text = "Form1";
            this.Load += new System.EventHandler(this.Form1_Load);
            this.ResumeLayout(false);
            this.PerformLayout();

        }

        #endregion
    }
}

窗体界面截图:

posted on 2016-11-14 11:28  印子  阅读(2736)  评论(0编辑  收藏  举报

导航