程序功能:用户在TextBox3中手动输入若干字符,选择复选框"任务1" or "任务2",然后点击提交,开启2个线程把TextBox3的内容按字符一个个输入到TextBox1和TextBox2中
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.Threading;
/*回调机制*/
namespace WindowsFormsApp_test
{
public partial class Form1 : Form
{
private delegate void WriteTextBox(char ch); //定义委托
private WriteTextBox writeTextBox1; //声明委托
private WriteTextBox writeTextBox2;
//声明委托,以实现回调机制
private delegate void WriteTextBoxCallback();
//操作文本1的回调
private WriteTextBoxCallback writeTexBox1Callback;
//操作文本2的回调
private WriteTextBoxCallback writeTexBox2Callback;
public Form1()
{
InitializeComponent();
//CheckForIllegalCrossThreadCalls = false;
writeTexBox1Callback = new WriteTextBoxCallback(DowriteTextBox1);
writeTexBox2Callback = new WriteTextBoxCallback(DowriteTextBox2);
}
private void button1_Click(object sender, EventArgs e)
{
//创建一个线程
if (true == checkBox1.Checked)
{
ThreadStart doTask1 = new ThreadStart(DoTask1);
Thread tskThread1 = new Thread(doTask1);
tskThread1.Start();
}
if (true == checkBox2.Checked)
{
ThreadStart doTask2 = new ThreadStart(DoTask2);
Thread tskThread2 = new Thread(doTask2);
tskThread2.Start();
}
}
private void DoTask1()
{
textBox1.Invoke(writeTexBox1Callback);
}
private void DoTask2()
{
textBox2.Invoke(writeTexBox2Callback);
}
private void WriteText(WriteTextBox wMethod)
{
string strdata = textBox3.Text;
for (int i = 0; i < strdata.Length; i++)
{
wMethod(strdata[i]);
DateTime now = DateTime.Now;
while (now.AddMilliseconds(100) > DateTime.Now) { }
}
}
private void DowriteTextBox1()
{
groupBox2.Text = "运行中...";
groupBox2.Refresh();
textBox1.Clear();
textBox1.Refresh();
writeTextBox1 = new WriteTextBox(WriteText1);
WriteText(writeTextBox1);
groupBox2.Text = "任务1";
}
private void DowriteTextBox2()
{
groupBox3.Text = "运行中...";
groupBox3.Refresh();
textBox2.Clear();
textBox2.Refresh();
writeTextBox2 = new WriteTextBox(WriteText2);
WriteText(writeTextBox2);
groupBox3.Text = "任务2";
}
//回调方法
private void WriteText1(char ch)
{
textBox1.AppendText(ch + "\r");
}
private void WriteText2(char ch)
{
textBox2.AppendText(ch + "\r");
}
}
}
书上的原代码:
namespace WindowsFormsApp_test
{
public partial class Form1 : Form
{
private delegate void WriteTextBox(char ch); //定义委托
private WriteTextBox writeTextBox1; //声明委托
private WriteTextBox writeTextBox2;
//声明委托,以实现回调机制
private delegate void WriteTextBoxCallback(char ch);
//操作文本1的回调
private WriteTextBoxCallback writeTexBox1Callback;
//操作文本2的回调
private WriteTextBoxCallback writeTexBox2Callback;
//操作"任务1"分组框的回调
private delegate void ShowGroupBoxCallback(string str);
private ShowGroupBoxCallback showGroupBox2Callback;
//操作"任务2"分组框的回调
private ShowGroupBoxCallback showGroupBox3Callback;
public Form1()
{
InitializeComponent();
//CheckForIllegalCrossThreadCalls = false;
writeTexBox1Callback = new WriteTextBoxCallback(WriteText1);
writeTexBox2Callback = new WriteTextBoxCallback(WriteText2);
showGroupBox2Callback = new ShowGroupBoxCallback(ShGroup2);
showGroupBox3Callback = new ShowGroupBoxCallback(ShGroup3);
}
private void button1_Click(object sender, EventArgs e)
{
//创建一个线程
if (true == checkBox1.Checked)
{
groupBox2.Text = "运行中...";
groupBox2.Refresh();
textBox1.Clear();
textBox1.Refresh();
ThreadStart doTask1 = new ThreadStart(DoTask1);
Thread tskThread1 = new Thread(doTask1);
tskThread1.Start();
}
if (true == checkBox2.Checked)
{
groupBox3.Text = "运行中...";
groupBox3.Refresh();
textBox2.Clear();
textBox2.Refresh();
ThreadStart doTask2 = new ThreadStart(DoTask2);
Thread tskThread2 = new Thread(doTask2);
tskThread2.Start();
}
}
private void DoTask1()
{
writeTextBox1 = new WriteTextBox(DowriteTextBox1);
WriteText(writeTextBox1);
//组合框回调
groupBox2.Invoke(showGroupBox2Callback, "任务1");
}
private void DoTask2()
{
writeTextBox2 = new WriteTextBox(DowriteTextBox2);
WriteText(writeTextBox2);
groupBox3.Invoke(showGroupBox3Callback, "任务2");
}
private void WriteText(WriteTextBox wMethod)
{
string strdata = textBox3.Text;
for (int i = 0; i < strdata.Length; i++)
{
wMethod(strdata[i]);
DateTime now = DateTime.Now;
while (now.AddMilliseconds(100) > DateTime.Now) { }
}
}
private void DowriteTextBox1(char ch)
{
textBox1.Invoke(writeTexBox1Callback, ch);
}
private void DowriteTextBox2(char ch)
{
textBox2.Invoke(writeTexBox2Callback, ch);
}
//回调方法
private void WriteText1(char ch)
{
textBox1.AppendText(ch + "\r");
}
private void WriteText2(char ch)
{
textBox2.AppendText(ch + "\r");
}
private void ShGroup2(string str)
{
groupBox2.Text = str;
}
private void ShGroup3(string str)
{
groupBox3.Text = str;
}
}
}
21 个解决方案
#1
Control的Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行的。也就是说如果你的委托方法用来取花费时间长的数据,然后更新界面什么的,千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死。
#2
Control的BeginInvoke是相对于调用它的线程,即beginInvokeThread相对是异步的。
因此,我们可以想到。如果要异步取耗费长时间的数据,比如从数据库中读大量数据,我们应该这么做。
(1)如果你想阻止调用线程,那么调用代码(三),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
(2)如果你不想阻止调用线程,那么调用代码(四),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
http://www.cnblogs.com/mashang/archive/2009/08/01/1536730.html
因此,我们可以想到。如果要异步取耗费长时间的数据,比如从数据库中读大量数据,我们应该这么做。
(1)如果你想阻止调用线程,那么调用代码(三),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
(2)如果你不想阻止调用线程,那么调用代码(四),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
http://www.cnblogs.com/mashang/archive/2009/08/01/1536730.html
#3
你的意思是说,我的代码DowriteTextBox1和DowriteTextBox2花费的时间太长导致的?
#4
而书上的代码WriteText1和WriteText2花费时间短??
#5
顶啊。。。。。
#6
#7
private void DowriteTextBox1()
{
groupBox2.Text = "运行中...";
groupBox2.Refresh();
textBox1.Clear();
textBox1.Refresh();
writeTextBox1 = new WriteTextBox(WriteText1);
WriteText(writeTextBox1);
groupBox2.Text = "任务1";
}
private void DowriteTextBox2()
{
groupBox3.Text = "运行中...";
groupBox3.Refresh();
textBox2.Clear();
textBox2.Refresh();
writeTextBox2 = new WriteTextBox(WriteText2);
WriteText(writeTextBox2);
groupBox3.Text = "任务2";
}
这里写入控件操作是有问题的
应该改成
private void DowriteTextBox1()
{
writeTextBox1 = new WriteTextBox(WriteText1);
WriteText(writeTextBox1);
}
private void DowriteTextBox2()
{
writeTextBox2 = new WriteTextBox(WriteText2);
WriteText(writeTextBox2);
}
#8
控件都是在主线程上运行的,委托是在另一个线程中运行的,你在另一个线程操作还操作主线程上的控件,就是会出问题的
#9
是通过Invoke调的啊。。
#10
http://download.csdn.net/detail/jingwei12345/7382707
#11
Invoke会阻塞主线程,你的代码用Thread执行Invoke,依然会阻塞主线程
原书中的例子每个Invoke只执行一个ch,另一个线程就能跟着操作ui了。两个线程轮流invoke一个ch,看着就像同步进行了
你的代码是Invoke执行全部的ch,自然阻塞住了,另一个线程只能等待全部的操作结束才能运行了
大概是这样吧
原书中的例子每个Invoke只执行一个ch,另一个线程就能跟着操作ui了。两个线程轮流invoke一个ch,看着就像同步进行了
你的代码是Invoke执行全部的ch,自然阻塞住了,另一个线程只能等待全部的操作结束才能运行了
大概是这样吧
#12
我是这样实现的
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.Threading;
namespace WindowsFormsApplication16
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate void WriteRichTextBoxDelegate(string msg);
WriteRichTextBoxDelegate wr1,wr2;
private void writeRichTextBox1(string msg)
{
richTextBox1.AppendText(msg + "\r\n");
richTextBox1.ScrollToCaret();
}
private void writeRichTextBox2(string msg)
{
richTextBox2.AppendText(msg + "\r\n");
richTextBox2.ScrollToCaret();
}
private void writeRichTextBoxThread1()
{
while (true)
{
this.BeginInvoke(wr1, textBox1.Text);
Thread.Sleep(1000);
}
}
private void writeRichTextBoxThread2()
{
while (true)
{
this.BeginInvoke(wr2, textBox1.Text);
Thread.Sleep(1000);
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread tskThread1=new Thread(new ThreadStart(writeRichTextBoxThread1));
Thread tskThread2=new Thread(new ThreadStart(writeRichTextBoxThread2));
tskThread1.Start();
tskThread2.Start();
}
private void Form1_Load(object sender, EventArgs e)
{
wr1 = new WriteRichTextBoxDelegate(writeRichTextBox1);
wr2 = new WriteRichTextBoxDelegate(writeRichTextBox2);
}
}
}
#13
就按照楼上所写。其实觉得可以优化下,没有必要非要写个委托方法,比如:
其中 MethodInvoker 完全可以代替,感觉楼上写的有点复杂化。
Invoke((MethodInvoker) (() =>
{
txt_log.AppendText("--------------------成功【更新】实时库存数据,仓库: " +
Convert.ToInt32(_listOnStorage[0]) + "");
txt_log.AppendText("\n");
}));
其中 MethodInvoker 完全可以代替,感觉楼上写的有点复杂化。
#14
你弄个附件吧,我这边调试不通过
#15
没看懂你的语法。。。
“ Invoke((MethodInvoker) (() =>” 这个是啥意思?
#16
你这个跟我那代码有啥本质区别啊。
AppendText(msg + "\r\n");
只是我是按字符一个一个操作,你是一下子操作完。。
#17
你仔细看自己的代码跟书上的代码有啥区别.
书上操作groupbox也是用的委托,而你是直接操作的.
这就是区别所在.
书上操作groupbox也是用的委托,而你是直接操作的.
这就是区别所在.
#18
导致textbox虽然是异步操作的,但是在操作groupbox的时候是同步的
所以线程2要等线程1全部操作完成了才能运行
所以线程2要等线程1全部操作完成了才能运行
#19
或者你就是不想用委托去操作groupbox,就把操作groupbox的代码写到线程函数的外面去,不要写到线程里.
#20
MethodInvoker你不知道是什么意思,可以复制到代码里 看下注释,后面()=> 是个lamba 表达方法。可以省去你定义一个一个delegate。。。。
#21
或者你就是不想用委托去操作groupbox,就把操作groupbox的代码写到线程函数的外面去,不要写到线程里.
private void button1_Click(object sender, EventArgs e)
{
//创建一个线程
if (true == checkBox1.Checked)
{
groupBox2.Text = "运行中...";
groupBox2.Refresh();
textBox1.Clear();
textBox1.Refresh();
ThreadStart doTask1 = new ThreadStart(DoTask1);
Thread tskThread1 = new Thread(doTask1);
tskThread1.Start();
groupBox2.Text = "任务1";
}
if (true == checkBox2.Checked)
{
groupBox3.Text = "运行中...";
groupBox3.Refresh();
textBox2.Clear();
textBox2.Refresh();
ThreadStart doTask2 = new ThreadStart(DoTask2);
Thread tskThread2 = new Thread(doTask2);
tskThread2.Start();
groupBox3.Text = "任务2";
}
}
private void DowriteTextBox1()
{
writeTextBox1 = new WriteTextBox(WriteText1);
WriteText(writeTextBox1);
}
private void DowriteTextBox2()
{
writeTextBox2 = new WriteTextBox(WriteText2);
WriteText(writeTextBox2);
}
这个我试过了,也不行。。。哎,还是按书上的来吧。。。
#1
Control的Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行的。也就是说如果你的委托方法用来取花费时间长的数据,然后更新界面什么的,千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死。
#2
Control的BeginInvoke是相对于调用它的线程,即beginInvokeThread相对是异步的。
因此,我们可以想到。如果要异步取耗费长时间的数据,比如从数据库中读大量数据,我们应该这么做。
(1)如果你想阻止调用线程,那么调用代码(三),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
(2)如果你不想阻止调用线程,那么调用代码(四),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
http://www.cnblogs.com/mashang/archive/2009/08/01/1536730.html
因此,我们可以想到。如果要异步取耗费长时间的数据,比如从数据库中读大量数据,我们应该这么做。
(1)如果你想阻止调用线程,那么调用代码(三),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
(2)如果你不想阻止调用线程,那么调用代码(四),代码段D删掉,C改为耗费长时间的操作,因为这个操作是在另外一个线程中做的。代码段E改为更新界面的方法。
http://www.cnblogs.com/mashang/archive/2009/08/01/1536730.html
#3
Control的Invoke和BeginInvoke的委托方法是在主线程,即UI线程上执行的。也就是说如果你的委托方法用来取花费时间长的数据,然后更新界面什么的,千万别在UI线程上调用Control.Invoke和Control.BeginInvoke,因为这些是依然阻塞UI线程的,造成界面的假死。
你的意思是说,我的代码DowriteTextBox1和DowriteTextBox2花费的时间太长导致的?
#4
而书上的代码WriteText1和WriteText2花费时间短??
#5
顶啊。。。。。
#6
#7
private void DowriteTextBox1()
{
groupBox2.Text = "运行中...";
groupBox2.Refresh();
textBox1.Clear();
textBox1.Refresh();
writeTextBox1 = new WriteTextBox(WriteText1);
WriteText(writeTextBox1);
groupBox2.Text = "任务1";
}
private void DowriteTextBox2()
{
groupBox3.Text = "运行中...";
groupBox3.Refresh();
textBox2.Clear();
textBox2.Refresh();
writeTextBox2 = new WriteTextBox(WriteText2);
WriteText(writeTextBox2);
groupBox3.Text = "任务2";
}
这里写入控件操作是有问题的
应该改成
private void DowriteTextBox1()
{
writeTextBox1 = new WriteTextBox(WriteText1);
WriteText(writeTextBox1);
}
private void DowriteTextBox2()
{
writeTextBox2 = new WriteTextBox(WriteText2);
WriteText(writeTextBox2);
}
#8
控件都是在主线程上运行的,委托是在另一个线程中运行的,你在另一个线程操作还操作主线程上的控件,就是会出问题的
#9
控件都是在主线程上运行的,委托是在另一个线程中运行的,你在另一个线程操作还操作主线程上的控件,就是会出问题的
是通过Invoke调的啊。。
#10
有没有代码文件呀
http://download.csdn.net/detail/jingwei12345/7382707
#11
Invoke会阻塞主线程,你的代码用Thread执行Invoke,依然会阻塞主线程
原书中的例子每个Invoke只执行一个ch,另一个线程就能跟着操作ui了。两个线程轮流invoke一个ch,看着就像同步进行了
你的代码是Invoke执行全部的ch,自然阻塞住了,另一个线程只能等待全部的操作结束才能运行了
大概是这样吧
原书中的例子每个Invoke只执行一个ch,另一个线程就能跟着操作ui了。两个线程轮流invoke一个ch,看着就像同步进行了
你的代码是Invoke执行全部的ch,自然阻塞住了,另一个线程只能等待全部的操作结束才能运行了
大概是这样吧
#12
我是这样实现的
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.Threading;
namespace WindowsFormsApplication16
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private delegate void WriteRichTextBoxDelegate(string msg);
WriteRichTextBoxDelegate wr1,wr2;
private void writeRichTextBox1(string msg)
{
richTextBox1.AppendText(msg + "\r\n");
richTextBox1.ScrollToCaret();
}
private void writeRichTextBox2(string msg)
{
richTextBox2.AppendText(msg + "\r\n");
richTextBox2.ScrollToCaret();
}
private void writeRichTextBoxThread1()
{
while (true)
{
this.BeginInvoke(wr1, textBox1.Text);
Thread.Sleep(1000);
}
}
private void writeRichTextBoxThread2()
{
while (true)
{
this.BeginInvoke(wr2, textBox1.Text);
Thread.Sleep(1000);
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread tskThread1=new Thread(new ThreadStart(writeRichTextBoxThread1));
Thread tskThread2=new Thread(new ThreadStart(writeRichTextBoxThread2));
tskThread1.Start();
tskThread2.Start();
}
private void Form1_Load(object sender, EventArgs e)
{
wr1 = new WriteRichTextBoxDelegate(writeRichTextBox1);
wr2 = new WriteRichTextBoxDelegate(writeRichTextBox2);
}
}
}
#13
就按照楼上所写。其实觉得可以优化下,没有必要非要写个委托方法,比如:
其中 MethodInvoker 完全可以代替,感觉楼上写的有点复杂化。
Invoke((MethodInvoker) (() =>
{
txt_log.AppendText("--------------------成功【更新】实时库存数据,仓库: " +
Convert.ToInt32(_listOnStorage[0]) + "");
txt_log.AppendText("\n");
}));
其中 MethodInvoker 完全可以代替,感觉楼上写的有点复杂化。
#14
你弄个附件吧,我这边调试不通过
我是这样实现的
[code=csharp]
#15
就按照楼上所写。其实觉得可以优化下,没有必要非要写个委托方法,比如:
Invoke((MethodInvoker) (() =>
{
txt_log.AppendText("--------------------成功【更新】实时库存数据,仓库: " +
Convert.ToInt32(_listOnStorage[0]) + "");
txt_log.AppendText("\n");
}));
其中 MethodInvoker 完全可以代替,感觉楼上写的有点复杂化。
没看懂你的语法。。。
“ Invoke((MethodInvoker) (() =>” 这个是啥意思?
#16
我是这样实现的
你这个跟我那代码有啥本质区别啊。
AppendText(msg + "\r\n");
只是我是按字符一个一个操作,你是一下子操作完。。
#17
你仔细看自己的代码跟书上的代码有啥区别.
书上操作groupbox也是用的委托,而你是直接操作的.
这就是区别所在.
书上操作groupbox也是用的委托,而你是直接操作的.
这就是区别所在.
#18
导致textbox虽然是异步操作的,但是在操作groupbox的时候是同步的
所以线程2要等线程1全部操作完成了才能运行
所以线程2要等线程1全部操作完成了才能运行
#19
或者你就是不想用委托去操作groupbox,就把操作groupbox的代码写到线程函数的外面去,不要写到线程里.
#20
就按照楼上所写。其实觉得可以优化下,没有必要非要写个委托方法,比如:
Invoke((MethodInvoker) (() =>
{
txt_log.AppendText("--------------------成功【更新】实时库存数据,仓库: " +
Convert.ToInt32(_listOnStorage[0]) + "");
txt_log.AppendText("\n");
}));
其中 MethodInvoker 完全可以代替,感觉楼上写的有点复杂化。
没看懂你的语法。。。
“ Invoke((MethodInvoker) (() =>” 这个是啥意思?
MethodInvoker你不知道是什么意思,可以复制到代码里 看下注释,后面()=> 是个lamba 表达方法。可以省去你定义一个一个delegate。。。。
#21
或者你就是不想用委托去操作groupbox,就把操作groupbox的代码写到线程函数的外面去,不要写到线程里.
private void button1_Click(object sender, EventArgs e)
{
//创建一个线程
if (true == checkBox1.Checked)
{
groupBox2.Text = "运行中...";
groupBox2.Refresh();
textBox1.Clear();
textBox1.Refresh();
ThreadStart doTask1 = new ThreadStart(DoTask1);
Thread tskThread1 = new Thread(doTask1);
tskThread1.Start();
groupBox2.Text = "任务1";
}
if (true == checkBox2.Checked)
{
groupBox3.Text = "运行中...";
groupBox3.Refresh();
textBox2.Clear();
textBox2.Refresh();
ThreadStart doTask2 = new ThreadStart(DoTask2);
Thread tskThread2 = new Thread(doTask2);
tskThread2.Start();
groupBox3.Text = "任务2";
}
}
private void DowriteTextBox1()
{
writeTextBox1 = new WriteTextBox(WriteText1);
WriteText(writeTextBox1);
}
private void DowriteTextBox2()
{
writeTextBox2 = new WriteTextBox(WriteText2);
WriteText(writeTextBox2);
}
这个我试过了,也不行。。。哎,还是按书上的来吧。。。