InvokeRequired与Invoke
在多线程应用中将会涉及不同的线程访问同一控件的问题,C#中禁止跨线程直接访问控件。某个控件在被创建时就记下了是谁创建了它,即它的创建线程。如果从另一个线程调用该控件,那么必须使用控件的 Invoke 方法来将调用封送现在调用它的线程。(Invoke方法是控件的方法)
到底是哪个线程要使用该控件呢?需要用InvokeRequired来询问一下,如果当前调用线程不是控件的创建线程,则为 true;否则为 false。
例子:
代码段前提是lb是一个label控件,在主线程创建(不用了解具体在哪个线程,反正和RunTimer不在一个线程),RunTimer方法是在另一个线程创建,这时候我们需要RunTimer方法调用主线程上的label控件。
private delegate void RunTimeDelegate(); private void RunTime() { if (lb.InvokeRequired) { RunTimeDelegate d = RunTime; lb.Invoke(d);//Invoke方法是控件的,这里相当于把RunTime方法交于了委托d, //d中相当于把RunTimer方法从线程中提取出来放到委托中,此时控件的Invoke方法就可以 // 调用委托中的和RunTimer相同方法,这样控件使用RunTimer方法就在控件的线程中使用的。 } else { time = endTime - TimeSpan.Parse(DateTime.Now.ToString("HH:mm:ss")); lb.Text = time.ToString(); } }
,这里添加几个实例,第一个是无参数传递,跨线程控制picturebox1控件
private delegate void DrawOnePicDelegate();//跨线程调用pictureBox1
public void DrawOnePicture()
{
if (pictureBox1.InvokeRequired)//如果控件被非本线程调用,则返回true
{
DrawOnePicDelegate d = new DrawOnePicDelegate (DrawOnePicture);//将方法放入委托
this.pictureBox1.Invoke(d);//从从控件创建线程中调用该方法
}
else
{
//方法
}
另一个是带参数传递控制listbox的内容,传入的参数就是list中应该显示的text
delegate void AddItemCallback(string text);
//这种方法演示如何在线程安全的模式下调用Windows窗体上的控件。
private void AddItem(string text)
{
if (this.listBox1.InvokeRequired)
{
AddItemCallback d = new AddItemCallback(AddItem);
this.Invoke(d, new object[] { text });
}
else
{
this.listBox1.Items.Add(text);
}
}
添加一个自己在实践中遇到的问题:问题大致描述:首先开辟一个线程,线程中方法实现在label控件上实现秒计数。
这里添加最开始错误的代码:
G_th = new System.Threading.Thread(ShowText);
G_th.IsBackground = true;//设置线程为后台线程
G_th.Start();//开始执行线程
//以上为建立一个线程,线程名字为G_th。
private delegate void ShowTextDelegate();
public void ShowText()
{
int P_int_count = 0;
while (true)
{
P_int_count = ++P_int_count > 1000000 ? 0 : P_int_count;//计数器累加
if (lb_time.InvokeRequired)
{
ShowTextDelegate d = new ShowTextDelegate(ShowText);
lb_time.Invoke(d);
}
else
{
lb_time.Text = P_int_count.ToString();
}
// Thread.Sleep(1000);//线程睡眠1秒
}
}
上述代码运行时会出现卡死,原因在于while的循环问题,至于为什么,我也没搞懂,哪位大神看到了也可以帮小弟解答下,后来我改了代码成为下面的样子,运行成功。我把while的循环放在了外面,label的委托仅仅只判断label的引用线程,所以,在平时工作中,应当注意,尽量不要在控件的委托中调用循环。
G_th.IsBackground = true;//设置线程为后台线程
G_th.Start();//开始执行线程
public void AddCount()
{
P_int_count = 0;
while (true)
{
P_int_count = ++P_int_count > 1000000 ? 0 : P_int_count;//计数器累加
ShowText();
Thread.Sleep(1000);//线程睡眠1秒
}
}
private delegate void ShowTextDelegate();
public void ShowText()
{
if (lb_time.InvokeRequired)
{
ShowTextDelegate d = new ShowTextDelegate(ShowText);
lb_time.Invoke(d);
}
else
{
lb_time.Text = P_int_count.ToString();//窗体中显示计数
}
}
posted on 2017-12-04 19:28 Yulong5759 阅读(872) 评论(0) 收藏 举报
浙公网安备 33010602011771号