我有一个类似“ClientSocket.cs”的类
class ClientSocket {
public delegate void ConnectHandler(object sender, EventArgs e);
public event ConnectHandler ConnectEvent = delegate { };
protected void OnConnectEvent(EventArgs e) {
ConnectHandler ev = ConnectEvent;
ev(this, e);
}
}
还有另一个类“myForm.cs”
public partial class myForm : Form {
private ClientSocket client;
private void button1_Click(object sender, EventArgs e) {
client = new ClientSocket();
client.ConnectEvent += myForm_OnConnectEvent;
client.connect();
}
// Handler for ConnectEvent
private void myForm_OnConnectEvent(object sender, EventArgs e) {
//this.BeginInvoke((MethodInvoker)delegate { writeLog("Connected"); });
writeLog("Connected");
}
// Function that write a log string to a TextBox
public writeLog(string log) {
guiTextBox.AppendText(log);
}
}
问题来了。 我尝试使用 BeginInvoke 调用 writeLog 或直接调用它。有时,我在写入 guiTextBox 时会收到 InvalidOperationException。 我不明白为什么我会收到这条消息。该事件由 ClientSocket 对象触发,但事件处理程序与主 UI 线程 (myForm) 相关。
我可以避免对类的每个 EventHandler 使用 BeginInvoke/Invoke 吗?
<小时/>编辑:我明白有什么区别,现在我尝试了解调用事件的最佳实践。
当在 BASE 类中引发事件时,我是否应该放置 BeginInvoke/Invoke 方法(在这种情况下为 ClientSocket)
protected void OnConnectEvent(EventArgs e) {
ConnectHandler ev = ConnectEvent;
this.BeginInvoke((MethodInvoker)delegate { ev(this, e);});
}
或者我应该把它当我使用该对象并向该处理程序添加监听器时
// Handler for ConnectEvent used in GUI (myForm)
private void myForm_OnConnectEvent(object sender, EventArgs e) {
this.BeginInvoke((MethodInvoker)delegate { writeLog("Connected"); });
}
干杯
最佳答案
ClientSocket
内的 this.BeginInvoke
不存在。为了能够执行 BeginInvoke
,必须在具有该方法的对象上调用它(在您的情况下为您的表单)。
如果您希望在 ClientSocket 类内部进行调用,则需要传入具有 BeginInvoke
函数的 Control
。
但是,如果我写这篇文章,我就不会采用这种方法。它向 ClientSocket
添加了一个不必要的要求,即您必须传入一个Control
(这称为 Tightly Coupling并且您应该在编程中尽量避免它)。就我个人而言,我会让事件在它想要引发的任何线程中传递,并让消费者担心进行任何特殊调用(如果他们甚至需要的话)。
这是我编写myForm_OnConnectEvent
的方式,该模式检查我们是否需要调用,如果需要,它会使用相同的参数再次调用该函数,但这次是在 UI 线程上。
// Handler for ConnectEvent used in GUI (myForm)
private void myForm_OnConnectEvent(object sender, EventArgs e)
{
if(this.InvokeRequired)
{
this.BeginInvoke(new ConnectHandler(myForm_OnConnectEvent), new object[] {sender, e});
return;
}
writeLog("Connected");
}
<小时/>
顺便说一句,我不知道 writeLog
正在做什么( it should have a capital W by the way ),但如果它不与 UI 交互,则根本不需要执行任何调用。如果它与 TextBox
或 UI 上的其他内容交互,那就是我进行调用的地方。
private void myForm_OnConnectEvent(object sender, EventArgs e)
{
writeLog("Connected");
}
private void writeLog(string logMessage)
{
if(logTextBox.InvokeRequired)
{
logTextBox.BeginInvoke(new Action<string>(writeLog), logMessage);
return;
}
var logLine = String.Format("{0:g}: {1}{2}", DateTime.Now, logMessage, Enviorment.NewLine);
logTextBox.AppendText(logLine);
}
关于c# - 使用事件处理程序进行 GUI 调用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19916251/