试图弄清楚为什么实现回调的windows窗体不起作用。
我想做的事:
- 按下一个按钮,就会调用服务
- 服务调用回表单(函数的IsOneWay=true)
- 表单相应地更新GUI
UseSynchronizationContext为false并在GUI成员上调用Invoke工作正常:
[CallbackBehavior(UseSynchronizationContext = false)]
public class DeliveryClient : System.Windows.Forms.Form, ICallback
{
public void ServiceCallback(string system, string state, string extraInfo)
{
if (state == "start")
{
Invoke((MethodInvoker)delegate { picBox.Visible = true; });
}
else
{
Invoke((MethodInvoker)delegate { picBox.Visible = false; });
}
}
}
但是UseSynchronizationContext=true,并且直接调用成员不会:
[CallbackBehavior(UseSynchronizationContext = true)]
public class DeliveryClient : System.Windows.Forms.Form, ICallback
{
public void ServiceCallback(string system, string state, string extraInfo)
{
if (state == "start")
{
picBox.Visible = true;
}
else
{
picBox.Visible = false;
}
}
使用SyynchronizationContext也不是字面意义上的
SynchronizationContext.Current.Send(_=> picBox.Visible = true, null);
第二个和第三个版本也应该工作吗?回调被称为OneWay,因此服务在回调后继续。
您的Form
类真的是WCF服务客户端回调的实现吗,正如WCF所知(即不仅仅是您从WCF客户端委托的东西)?如果没有,则说明[CallbackBehavior]
属性放错了位置。正如文件所述:
CallbackBehaviorAttribute必须应用于实现回调约定的类
如果它是客户端回调的实现,那么如果没有一个好的Minimal、Complete和Verifible代码示例,我恐怕无法说明为什么该属性没有达到预期效果。但我可以说,如果真的是这样的话,你的代码设计得很糟糕。将UI与服务客户端回调实现相结合违反了健康代码的许多OOP原则,但最重要的是违反了关注点分离原则。
就目前而言:
SynchronizationContext.Current.Send(_=> picBox.Visible = true, null);
这不是您应该如何使用SynchronizationContext
。Current
属性返回当前正在运行的线程的上下文。当您需要调用Send()
时,检索上下文已经太晚了。创建对象时,需要将SynchronizationContext.Current
存储在希望执行Send()
调用的委托的线程中(当然,该线程必须具有有用的上下文,例如在Winforms程序的主UI线程中)。
如果以上内容不能为您提供足够的信息来使代码正常工作,请通过提供可靠再现问题的良好MCVE来改进问题。