在 .Net Framework 2.0 中如果跨线程调用控件会出现错误(
InvalidOperationException 从不是创建控件
control name 的线程访问它。)如
test() 函数可能是跨线程的向
Form1 的
listBox1 中加入项:
解决它的一种方法是在窗体设计器生成的代码中加入
但这样就回到了 1.1 版本时代,显然不符合时代发展需要,所以另一种方法是要用安全的委托,利用出错时对象的
InvokeRequired 属性的值将为
true 的原理用
Invoke() 函数来处理。
[C#]
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Text;
using
System.Windows.Forms;

namespace
Test

...
{
public partial class Form1 : Form

...{
......
//定义一个 CallBack 函数
delegate void AddItemsCallBack(String s);

//CallBack 指向的函数
public void AddItems(String s)

...{
AddItemsCallBack cb = new AddItemsCallBack(AddItems);
if (this.listBox1.InvokeRequired)

this.listBox1.Invoke(cb, new object[] ...{ s });
else
this.listBox1.Items.Add(s);
}
......
}
}
[Visual Basic]
Public Class Form1
Class Form1
......
'定义一个 CallBack 函数

Delegate Sub AddItemsCallBack()Sub AddItemsCallBack(ByVal s As String)

'CallBack 指向的函数

Public Sub AddItems()Sub AddItems(ByVal s As String)
Dim cb As New AddItemsCallBack(AddressOf AddItems)
If Me.ListBox1.InvokeRequired Then
Me.ListBox1.Invoke(cb, New Object() {s})
Else
Me.ListBox1.Items.Add(s)
End If
End Sub
......
End Class
此外,当我们使用自定义方法操作控件时有时会发生空间代码被执行两次的现象,这个主要是由于事件被主动注册的缘故,使用
object.
Events.Dispose() 来禁用事件列表。
[C#]
using
System;
using
System.Collections.Generic;
using
System.ComponentModel;
using
System.Data;
using
System.Drawing;
using
System.Text;
using
System.Windows.Forms;

namespace
LabScriptTest

...
{
public partial class Form1 : Form

...{
private void Form1_Load(object sender, EventArgs e)

...{
........
//禁用事件列表
this.Events.Dispose();
//设置
........
}
}
}
[Visual Basic]
Public Class Form1
Class Form1


Private Sub Form1_Load()Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
........
'禁用事件列表
Me.Events.Dispose()
'设置
........
End Sub

End Class
要注意的是,如果在设置之后再禁用事件列表将使窗体不能响应消息,另外,代码被重复执行的情况若发生在另一窗体中,在执行完程序并用
Form.Close() 关闭窗口后样式都不会改变,也就是说,下一次使用
Form.Show() 显示窗体时其加载时仍如前面关闭时一样。
若想在向窗体画图后立即更新窗体则需要使用 Invalidate() 函数,而不是 Update() 函数,前者会使全部区域无效而必须重新 Paint,后者只使未使用控件区域无效而重新 Paint。
......
//假设 test() 运行于一不安全线程下
void test()
{
......
Form1 frm = new Form1();
frm.listBox1.Items.Add("Test!" );
......
}
......
//假设 test() 运行于一不安全线程下
void test()
{
......
Form1 frm = new Form1();
frm.listBox1.Items.Add("Test!" );
......
}
......
System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;
[C#]



















































[C#]






































若想在向窗体画图后立即更新窗体则需要使用 Invalidate() 函数,而不是 Update() 函数,前者会使全部区域无效而必须重新 Paint,后者只使未使用控件区域无效而重新 Paint。