现在我想写一个带有界面的c#程序,当然我要采用UI部分和程序的实现部分分离的办法,现在我写了一个线程类,在UI启动时创建线程,这样两部分就可以分离工作了。
但是,在UI中要向子线程中传递信息,并且在子线程中处理完任务也要向UI返回信息。
问题:
UI与子线程的信息传递应该如何实现?
如果采用发送消息的方式,那么子线程向UI发送信息,UI要怎样做才能接受到子线程的消息?做好有代码实例。大虾帮忙,不胜感激。
但是,在UI中要向子线程中传递信息,并且在子线程中处理完任务也要向UI返回信息。
问题:
UI与子线程的信息传递应该如何实现?
如果采用发送消息的方式,那么子线程向UI发送信息,UI要怎样做才能接受到子线程的消息?做好有代码实例。大虾帮忙,不胜感激。
{
private Thread t=null;
...
public class ThreadClass
{
private bool isRunning=false;
...
public bool IsRunning
{
set{...}
get{...}
}
...
public void ThreadProc()
{
...
}
}
}
大概的框架是如此,创建线程之前,先创建一个ThreadClass的实例,通过这个实例来启动线程,通过实例的属性来与线程交换信息。
安全的方法是:代理
一、多线程实例,一个将域名解析成IP地址的程序:建立一个C# winform 程序 添加一个 timer 、一个progressBar、一个textbox、两个Button;将form的带面替换成以下代码:using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net ;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;//关闭线程互访的限制机制,目的 新线程可以访问主线程的文本框控件 }
public static string newstr (string str) //获取ip地址函数
{
try
{ IPHostEntry ip = new IPHostEntry();
ip = Dns.GetHostEntry(str); String ips="";
for (int i = 0; i < ip.AddressList.Length; i++)
{
ips = ips + ip.AddressList[i].ToString() + ";";
}
return ips.ToString();
}
catch(Exception err )
{ return err.ToString(); }
}
private void tex() //执行 获取 地址的过程
{
textBox1.Text = newstr(textBox1.Text.ToString());
MessageBox.Show(newstr(textBox1.Text.ToString()).ToString()); } private void timer1_Tick(object sender, EventArgs e)//time1控制进度条不断增长循环
{
if (progressBar1.Value < 100)
{
progressBar1.Value = progressBar1.Value + 1;
}
else
{
progressBar1.Value = 0;
}
}
private void button1_Click(object sender, EventArgs e) //按钮1的单击事件,使用线程
{
Thread t1 = new Thread(tex); //定义新线程
t1.Start();//开始 timer1.Enabled = true;//打开计时器
}
private void button2_Click(object sender, EventArgs e)//按钮2的单击事件 ,不使用线程
{
tex();
timer1.Enabled = true; }
}
} F5运行程序,在文版框内填入想要解析的 域名(最好是不存在的域名) 单击 Button1 可以看到 界面无停顿的解析结果;单击Button2 可以看到界面 有明显停顿。 二、代理(Delegate)C#中默认的情况下 线程是不允许互访的,为了安全性和稳定性,代码:private void Form1_Load(object sender, EventArgs e)
{
Control.CheckForIllegalCrossThreadCalls = false;//关闭线程互访的限制机制,目的 新线程可以访问主线程的文本框控件 }
可以关闭 此检查,但是此种方法 不安全,故使用 代理的方式 进行线程互访。代码如下: using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Net ;
namespace ThreadTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
} delegate void aa();//创建一个代理
public string s;//公共变量,返回线程执行的结果与主线程共享。
private void Form1_Load(object sender, EventArgs e)
{
//Control.CheckForIllegalCrossThreadCalls = false;//关闭线程互访的限制机制,目的 新线程可以访问主线程的文本框控件 }
public static string newstr (string str) //获取ip地址函数
{
Thread.Sleep(5000);
try
{ IPHostEntry ip = new IPHostEntry();
ip = Dns.GetHostEntry(str); String ips="";
for (int i = 0; i < ip.AddressList.Length; i++)
{
ips = ips + ip.AddressList[i].ToString() + ";";
}
return ips.ToString();
}
catch(Exception err )
{ return err.ToString(); }
}
private void setw()
{
textBox1.Text = s;
}
private void tex() //执行 获取 地址的过程
{
s=newstr(textBox1.Text.ToString());
textBox1.BeginInvoke(new aa(setw));
} private void timer1_Tick(object sender, EventArgs e)//time1控制进度条不断增长循环
{
if (progressBar1.Value < 100)
{
progressBar1.Value = progressBar1.Value + 1;
}
else
{
progressBar1.Value = 0;
}
}
private void changeText(string s)
{
textBox1.Text = s;
} private void button1_Click(object sender, EventArgs e) //按钮1的单击事件,使用线程
{
Thread t1 = new Thread(tex); //定义新线程
t1.Start();//开始
timer1.Enabled = true;//打开计时器
}
private void button2_Click(object sender, EventArgs e)//按钮2的单击事件 ,不使用线程
{
tex();
timer1.Enabled = true; }
}
} 其他:多线程访问主界面控件的方式就是 调用主线程的 一个方法来改变,我理解具体操作是有主线程完成的。实例2:using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
public delegate void 我的委托();//声明一个委托
public string s;//定义公共变量 ,方便线程共享。
public Form1()
{
InitializeComponent();
}
public static string newstr(string str) //获取ip地址函数-一个耗时的操作
{
try
{ IPHostEntry ip = new IPHostEntry();
ip = Dns.GetHostEntry(str); String ips = "";
for (int i = 0; i < ip.AddressList.Length; i++)
{
ips = ips + ip.AddressList[i].ToString() + ";";
}
return ips.ToString();
}
catch (Exception err)
{ return err.ToString(); }
}
public void 设置文字() //定义一个改变Button文字的方法
{
button1.Text = s;
} public void 新线程()
{
s = newstr("111a");
System.Threading.Thread.Sleep(5000);//线程休眠2秒
button1.BeginInvoke(new 我的委托(设置文字));//在button1所在线程上执行“设置文字”,这里的 设置文字函数必须 无参
} private void button1_Click_1(object sender, EventArgs e)
{
new System.Threading.Thread(new System.Threading.ThreadStart(新线程)).Start();//创建一个新的线程并启动 } private void timer1_Tick(object sender, EventArgs e) //控制进度条 显示 方便判断界面响应情况
{
if (progressBar1.Value < 100)
{
progressBar1.Value = progressBar1.Value + 1;
}
else
{
progressBar1.Value = 0;
} } private void Form1_Load(object sender, EventArgs e)
{
timer1.Enabled = true;
}
}}
谢谢解答,但是还是存在一个问题。
我的程序向实现一个下载的功能,当点击UI上的【开始】Button后,【开始】变灰色,UI传递下载地址给后台下载线程,当后台线程下载完成后,再通知UI,UI将【开始】Button还原。
采用你的方法后,UI可以将下载地址传递给后台线程,但是当后台通知UI下载完成时,UI不能立即响应这个下载完成的消息,请问怎样可以让UI立即响应,将【开始】Button还原为正常状态?TO bugers:
谢谢解答,但是还是存在一个问题。
我的程序想建立的线程类,当UI启动的时候实例化这个线程类,但是你的代码中的线程是一个函数,该如何在线程类中用托管,我不太懂,可不可以再给个线程类的代码?TO LQknife
这个方法没太看懂,正在看ing
2.不安全的方法,Control.CheckForIllegalCrossThreadCalls = false;然后在线程类中调用主窗体中某个方法改变按钮的状态。关于自定义事件,可参考:http://topic.csdn.net/u/20090805/16/41a8b980-02bb-4e6e-86d0-26967480b76f.html