线程下使用控件

redlei 2010-01-08 12:52:48
我想在线程中,使用richtextbox
但是,我在读取 的时候,不能直接 显示出来,直到线程退出,所有文本才能显示出来。。。
应该怎么做呢?
我带代码如下


启动线程部分
private void Form1_Load(object sender, EventArgs e)
{
this.richTextBox1.Text += "system all ready\n";
Control.CheckForIllegalCrossThreadCalls = false;
thThreadRead = new Thread(new ThreadStart(Listen));
thThreadRead.IsBackground = true;
thThreadRead.Start();//启动线程
}

下面是 函数部分

private void Listen()
{

try
{

tlTcpListen = new TcpListener(port);
tlTcpListen.Start();

tcClient = tlTcpListen.AcceptTcpClient();
nsStream = tcClient.GetStream();
srRead = new StreamReader(nsStream);

while (blistener)
{
string sMessage = srRead.ReadLine();
if (sMessage == "STOP")
{
tlTcpListen.Stop();
nsStream.Close();
srRead.Close();
thThreadRead.Abort();
return;
}
string sTime = DateTime.Now.ToShortTimeString();
this.richTextBox1.Text += sTime + " " + sMessage + "\n";

}
}

catch (System.Security.SecurityException)
{
MessageBox.Show("Listen failed", "Error");
}

}

请大家帮忙
...全文
177 11 打赏 收藏 转发到动态 举报
写回复
用AI写文章
11 条回复
切换为时间正序
请发表友善的回复…
发表回复
Carpathia 2010-01-11
  • 打赏
  • 举报
回复
System.Environment.Exit(0);
可以停止所有后台线程并关闭窗口
redlei 2010-01-11
  • 打赏
  • 举报
回复
请问,下面这种情况,为什么不能关闭窗口呢?窗口关闭了,但是,程序还在调试中。。。
为什么会这样呢?请各位赐教

public partial class Form1 : Form
{

public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
Thread newthread = new Thread(new ThreadStart(ttread));
newthread.Start();
}

void ttread()
{
pri(DateTime.Now.ToString());
}


#region 代理线程
delegate void aa(string s);//创建一个代理
private void pri(string t)//这个就是我们的函数,我们把要对控件进行的操作放在这里
{
if (!richTextBox1.InvokeRequired)//判断是否需要进行唤醒的请求,如果控件与主线程在一个线程内,可以写成if(!InvokeRequired)
{

richTextBox1.Text += t;
}
else
{
aa a1 = new aa(pri);
while(true)
{
try
{
Invoke(a1, new object[] { t });//执行唤醒操作
Thread.Sleep(100);
}
catch
{

}
}
}
}
#endregion

}
Carpathia 2010-01-08
  • 打赏
  • 举报
回复
线程下操作UI需要委托delegate,不能直接在线程里操作
liushengmz 2010-01-08
  • 打赏
  • 举报
回复
多线程中使用线程更改Control的内容或是状态,需要由创建该Control

的线程进行操作,这样的操作是安全的。但如果其它线程要更改Control

的内容或是状态的话,不能靠自己,只能通知创建该Control的线程进行

更改。一般用到委托去通知。用Invoke或是BeginInvoke,这两者的区别是

一个是等创建该Control的线程忙完后再处理,一个是命令它马上处理(但

该线程一定要有机会)否则它的用法也似第一种
cuike519 2010-01-08
  • 打赏
  • 举报
回复
namespace WindowsFormsApplication1 {

public delegate void Notify(int index);

public partial class Form1 : Form {

private Notify NotifyProgress;

public Form1() {
InitializeComponent();

this.NotifyProgress = new Notify(Noti);
}

private void Noti(int index) {
if (this.InvokeRequired) {
// 用当前线程调用委托
this.Invoke(this.NotifyProgress, new object[] { index });
}
else {
// 如果在当前线程则直接赋值,这里就不存在跨线程访问UI的问题了
this.label1.Text = index.ToString();
}
}

private void button1_Click(object sender, EventArgs e) {
Thread thread = new Thread(new ThreadStart(ThreadMethod));
thread.Start();
}

private void ThreadMethod() {
int i = 0;
while (true) {
// 这里模仿你的接受消息的逻辑,我这里等1秒钟
Thread.Sleep(1000);
i++;
// 这里调用委托,我传递一个int,你可以传递一个string出去
this.NotifyProgress(i);
}
}
}
}
流苏1990 2010-01-08
  • 打赏
  • 举报
回复
MethodInvoker del = delegate()
{
//*****
};
using System.Security.Cryptography;
hejialin666 2010-01-08
  • 打赏
  • 举报
回复
http://topic.csdn.net/u/20080818/17/5b2c8ae9-3eb5-4c73-b581-625457b70c9b.html
hejialin666 2010-01-08
  • 打赏
  • 举报
回复
由于Windows窗体控件本质上不是线程安全的。因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的bug,包括争用和死锁的情况。所以VS2005这一改动便可以增强线程安全性。
我想大家更关心的是如何解决这个问题,如何才能操作其它线程中的控件而不引发异常,接下来我们就来探讨下这个问题:

第一种方法:

这种方法我没用过,因为大家推荐不要使用,所以我没去实验过,具体方法如下(摘自网上):
设置System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;(winform.下)如果在你的程序初始化的时候设置了这个属性,而且在你的控件中使用的都是微软Framework类库中的控件的话,系统就不会再抛出你上面所说的这个错误了。当然这只是为了将VS2003的代码转换到VS2005下所使用的一种常见的方法。不建议采用;



第二种方法,也是我今天主要要讲的就是利用delegate和invoke这个方法:

思路:把想对另一线程中的控件实施的操作放到一个函数中,然后使用delegate代理那个函数,并且在那个函数中加入一个判断,用InvokeRequired来判断调用这个函数的线程是否和控件线程在同一线程中,如果是则直接执行对控件的操作,否则利用控件的Invoke或BeginInvoke方法来执行这个代理。

在继续讲解下去之前我们先来看一下这里提到的几个方法(如果对以下两个东东已经了解了就可以跳过)



首先是Invoke

Invoke的中文解释是唤醒,它有两种参数类型我们这里只讲一种即(Delegate, Object[])

Delegate就是前面提到的那个代理,而Object[]则是用来存放Delegate所代理函数的参数

MSDN上关于INVOKE方法有如下说明:在拥有控件的基础窗口句柄的线程上,用指定的参数列表执行指定委托。

用通俗的话讲就是利用控件的INVOKE方法,使该控件所在的线程执行这个代理,也就是执行我们想对控件进行的操作,相当于唤醒了这个操作;

其次是控件的InvokeRequired这个属性(个人翻译为’唤醒请求’):

MSDN上关于它的解释是获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用Invoke方法,因为调用方位于创建控件所在的线程以外的线程中。

有通俗的话讲就是返回一个值,如果与控件属于同一个线程,则不需要进行唤醒的请求,也就是返回值为False,否则则需要进行唤醒的请求,返回为true

总感觉MSDN上的翻译让人无法一看就明白,可能是自己智力不够吧~~



最后就是我们的具体程序了:


delegate void aa(string s);//创建一个代理
private void pri(string t)//这个就是我们的函数,我们把要对控件进行的操作放在这里
{
if (!richTextBox1.InvokeRequired)//判断是否需要进行唤醒的请求,如果控件与主线程在一个线程内,可以写成if(!InvokeRequired)
{
MessageBox.Show("同一线程内");
richTextBox1.Text =t;
}
else
{
MessageBox.Show("不是同一个线程");
aa a1 =new aa(pri);
Invoke(a1,new object []{t});//执行唤醒操作
}
}

private void Form1_Load(object sender, System.EventArgse)
{
Thread newthread = new Thread(new ThreadStart(ttread));
newthread.Start();
}

void ttread()
{
pri("sdfs");
}

执行结果先调出一个提示框显示“不是同一个线程”,然后跳出提示框显示“同一线程内”,然后richTextBox1中的text值为sdfs;这样便完成了对其它线程中的控件进行操作。


本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gisfarmer/archive/2008/07/31/2745426.aspx
whslovexyp 2010-01-08
  • 打赏
  • 举报
回复
FlushClient=new FlushClient(ThreadFunction);
FlushClient.BeginInvoke(null,null);
你至少声明个变量吧
FlushClient A=new FlushClient(ThreadFunction);
A.BeginInvoke(null,null);
纸纸纸纸飞飞 2010-01-08
  • 打赏
  • 举报
回复
类似这样使用:
if (control.InvokeRequired)
{
control.Invoke(new SetTextCallback(UpdateStatus), new object[] { control, type, user, totalcount });
}
else
{
if (control is Label)
{
Label label = control as Label;
string status = Resource.SR.GetString("Server_Status_" + type.ToString());
label.Text = string.Format(Resource.SR.GetString("Server_Status_UserInfomation"), user, status, totalcount);
return;
}

if (control is ListBox)
{
ListBox listbox = control as ListBox;

if (type == 0) // 用户登陆
{
listbox.Items.Add(user);
}
else if (type > 0) // 用户离线
{
if (listbox.Items.Contains(user))
listbox.Items.Remove(user);
}
}
}
redlei 2010-01-08
  • 打赏
  • 举报
回复
我用了 delegate
结果如下。。。
“xxxx.Form1.FlushClient”是“类型”,但此处被当做“变量”来使用
“xxxx.Form1.FlushClient.BeginInvoke(System.AsyncCallback, object)”要求对象引用

代码如下:

private delegate void FlushClient();//代理
private void Form1_Load(object sender, EventArgs e)
{
Thread thread = new Thread(CrossThreadFlush);
thread.IsBackground = true;
thread.Start();
}
private void CrossThreadFlush()
{
FlushClient=new FlushClient(ThreadFunction);
FlushClient.BeginInvoke(null,null);
}
private void ThreadFunction()
{
while (true)
{
this.textBox1.Text = DateTime.Now.ToString();
Thread.Sleep(1000);
}

}
}

110,536

社区成员

发帖
与我相关
我的任务
社区描述
.NET技术 C#
社区管理员
  • C#
  • Web++
  • by_封爱
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

让您成为最强悍的C#开发者

试试用AI创作助手写篇文章吧