我有一个winform和一个不断发送更新的接口回调。我希望能够从回调接口更新label1.Text。然而,因为inface在一个单独的线程上运行,我不认为我可以直接执行它所以我试图使用委托并调用。
但是我遇到了错误:
在创建窗口句柄之前,无法在控件上调用Invoke或BeginInvoke - 位于
form1.Invoke(form1.myDelegate, new Object[] { so.getString() });
这是完整的代码。
public partial class Form1 : Form
{
MyCallBack callback;
public delegate void UpdateDelegate(string myString);
public UpdateDelegate myDelegate;
public Form1()
{
InitializeComponent();
myDelegate = new UpdateDelegate(UpdateDelegateMethod);
callback = new MyCallBack(this);
CallBackInterfaceClass.SetCallBack(callback);
callback.OnUpdate();
}
public void UpdateDelegateMethod (String str)
{
label1.Text = str;
}
}
class MyTestCallBack : Callback
{
public Form1 form1;
public SomeObject so;
public MyTestCallBack(Form1 form)
{
this.form1 = form;
}
public void OnUpdate(SomeObject someobj)
{
so = someobj;
OnUpdate();
}
public void OnUpdate()
{
form1.Invoke(form1.myDelegate, new Object[] { so.getString() });
}
}
两个问题。
有谁能解释我做错了什么?
这实际上是最好的方法吗?
以下是基于bokibeg的回复(见下文)的答案,并进行了一些修改以使其有效:
public partial class Form1 : Form { MyTestCallBack _callback; public Form1() { InitializeComponent(); _callback = new MyTestCallBack(); _callback.MyTestCallBackEvent += callback_MyTestCallBackEvent; _callback.OnUpdate(); } private callback_MyTestCallBackEvent(MyTestCallBackEventArgs e) { if (InvokeRequired) { Invoke(new Action(() => { callback_MyTestCallBackEvent(sender, e); })); return; } label1.Text = e.SomeObject.GetDisplayString(); } class MyTestCallBackEventArgs : EventArgs { public SomeObject SomeObj { get; set; } } class MyTestCallBack : Callback { public event EventHandler<MyTestCallBackEventArgs> MyTestCallBackEvent; private SomeObject _so; protected virtual void OnMyTestCallBackEvent(MyTestCallBackEventArgs e) { if (MyTestCallBackEvent != null) MyTestCallBackEvent(this, e); } public void OnUpdate(SomeObject someobj) { _so = someobj; OnMyTestCallBackEvent(new MyTestCallBackEventArgs { SomeObject = _so }); } }
答案 0 :(得分:1)
这就是我要做的事情:
public partial class Form1 : Form
{
MyTestCallBack _callback;
public Form1()
{
InitializeComponent();
_callback = new MyTestCallBack();
_callback.MyTestCallBackEvent += callback_MyTestCallBackEvent;
_callback.OnUpdate();
}
private callback_MyTestCallBackEvent(MyTestCallBackEventArgs e)
{
// TODO: Invoke code here with e.g. label1.Text = e.SomeObj.ToString()...
}
}
class MyTestCallBackEventArgs : EventArgs
{
public SomeObject SomeObj { get; set; }
}
class MyTestCallBack : Callback
{
public event EventHandler<MyTestCallBackEventArgs> MyTestCallBackEvent;
private SomeObject _so;
public MyTestCallBack()
{
//
}
protected virtual void OnMyTestCallBackEvent(MyTestCallBackEventArgs e)
{
if (MyTestCallBackEvent != null)
MyTestCallBackEvent(e);
}
public void OnUpdate(SomeObject someobj)
{
_so = someobj;
OnMyTestCallBackEvent(new MyTestCallBackEventArgs { SomeObject = _so });
}
}
它将GUI逻辑与线程正在执行的操作分开。它会引发一场事件,而且它有责任随心所欲地做任何事情。
我不确定这是否编译,我是用文本垫写的。如果您有任何疑问,请告诉我。
你可能刚刚了解了代表并被其带走了,这与使用事件类似,但事件是正确放置在&#34;后端&#34;逻辑形式可能会也可能不会使用它。还要注意form的代码是如何更好的,它没有那么多的样板代码只是为了实现一些后台服务类。
但请注意,MyTestCallBackEvent
事件可能会在您关闭表单后继续触发,因此请确保在表单关闭或处理时取消订阅(或者当您觉得表单不再需要时)
哦,我差点忘了:你得到的原始错误是因为你在没有要求的情况下打电话给Invoke
而且Form肯定还没准备好。阅读此问题以查看how to safely invoke controls。