黑马程序员技术交流社区

标题: 学习笔记【八】—— Windows Form线程安全调用 [打印本页]

作者: jerviscui    时间: 2013-6-25 22:39
标题: 学习笔记【八】—— Windows Form线程安全调用
本帖最后由 jerviscui 于 2013-6-25 22:39 编辑


有如下代码,在新建的线程中调用textBox的方法时候,调试器报出异常。


using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace _01_socketclient
{
public partial class SocketClient : Form
{
  Thread receiveThread = null; //接受线程
  
  public SocketClient()
  {
   InitializeComponent();
  }

  private void btnConnection_Click(object sender, EventArgs e)
  {
   //实例接收线程
   receiveThread = new Thread(new ThreadStart(RecevieThread));
   //设置为后台线程
   receiveThread.IsBackground = true;
   //启动接受线程
   receiveThread.Start();
  }

  /// <summary>
  /// 显示文本信息
  /// </summary>
  /// <param name="msg"></param>
  private void ShowMsg(string msg)
  {
   txtShow.AppendText(msg + "\r\n");
  }

  /// <summary>
  /// 接收线程执行方法
  /// </summary>
  private void RecevieThread()
  {
   string strMsg = "hello world"
   ShowMsg(strMsg);
  }

}
}


原来是线程非安全方式访问控件。就是说,如果创建某控件的线程之外的其他线程试图调用该控件,则调试器会引发一个 InvalidOperationException,并提示消息:“从不是创建控件 control name 的线程访问它。”


可以通过将 CheckForIllegalCrossThreadCalls 属性的值设置为 false 来禁用此异常。

MSDN中提到了通过控件的 InvokeRequired 属性来判断调用控件的是哪一个线程,如果是非安全线程调用空间则使用实际调用空间的委托来调用Invoke。

Invoke(Delegate, array< Object []()>[] )         该方法的作用:在拥有此控件的基础窗口句柄的线程上执行指定的委托。


1.查询控件的 InvokeRequired 属性。

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

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

代码如下:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Net.Sockets;
using System.Net;
using System.Threading;

namespace _01_socketclient
{
public partial class SocketClient : Form
{
  Thread receiveThread = null; //接受线程
  delegate void SetTextCallback(string text);//invoke的方式实现安全调用
&nbsp;&nbsp;
  public SocketClient()
  {
   InitializeComponent();
  }
  private void btnConnection_Click(object sender, EventArgs e)
  {
   //实例接收线程
   receiveThread = new Thread(new ThreadStart(RecevieThread));
   //设置为后台线程
   receiveThread.IsBackground = true;
   //启动接受线程
   receiveThread.Start();
  }
  /// <summary>
  /// 显示文本信息
  /// </summary>
  /// <param name="msg"></param>
  private void ShowMsg(string msg)
{
  if (txtShow.InvokeRequired)
{</P><P>&nbsp;&nbsp;&nbsp;&nbsp;    SetTextCallback d = new SetTextCallback(ShowMsg); ;
Invoke(d, new object[] { msg });
}
else
{
txtShow.AppendText(msg + "\r\n");
}
}
  /// <summary>
  /// 接收线程执行方法
  /// </summary>
  private void RecevieThread()
  {
   string strMsg = "hello world"
   ShowMsg(strMsg);
  }
}
}

-The End-

© Jervis




作者: 许庭洲    时间: 2013-6-26 07:06
值得学习ing!




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2