我在执行WCF服务时遇到了更新WPF UI的问题,该服务在每个操作执行后都会向客户端发送消息。我使用WSDualHttpBinding。当我为来自服务的每条消息显示一个消息框时,同样的实现可以完美地工作。但这不能用于更新UI。
PS:我使用MVVM模式和Caliburn.micro我的实现简化了:
1 -接口: public interface IMyContractCallback
{
[OperationContract]
void OnCallback();
}
[ServiceContract(CallbackContract = typeof(IMyContractCallback))]
public interface IMyContract
{
[OperationContract]
void DoSomething();
}
2 -服务:[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant)]
public class MyService : IMyContract
{
public void DoSomething()
{
DoJob1();
var callbackChannel = OperationContext.Current.GetCallbackChannel<IMyContractCallback>();
callbackChannel.OnCallback();
DoJob2();
}
}
3 -客户:
- 回调实现:
public delegate void ClientNotifiedEventHandler(object sender, ClientNotifiedEventArgs e);
public class ClientNotifiedEventArgs : EventArgs
{
private readonly string _message;
public string Message { get { return _message; } }
public ClientNotifiedEventArgs(string message)
{
this._message = message;
}
}
[CallbackBehavior(ConcurrencyMode = ConcurrencyMode.Reentrant, UseSynchronizationContext = false)]
public class MyCallbackClient : IMyContractCallback
{
public event ClientNotifiedEventHandler ClientNotified;
public void OnCallback()
{
if (ClientNotified != null)
{
ClientNotified(this, new ClientNotifiedEventArgs(log));
}
}
}
视图模型实现:
公共类MyViewModel{
private string _message = "Loading.."; public string MessageLog { get { return _message; } set { _message = value; NotifyOfPropertyChange(() => MessageLog); } } public void DoTheJob() { var callback = new DbLoaderCallback(); callback.ClientNotified += Callback_ClientNotified; var context = new InstanceContext(callback); using (var serviceClient = new MyService(context)) { serviceClient.DoSomething(); } } private void Callback_ClientNotified(object sender, ClientNotifiedEventArgs e) { MessageLog += " n"; MessageLog += e.Message; }
}
这里,当调用callbackChannel.OnCallback();(在MyService上),当我们到达NotifyOfPropertyChange(() => MessageLog)时,它去到客户端,在MyViewModel上;它不会继续执行。所以DoJob2()从未执行过。
有谁知道到底是什么问题吗?提前感谢
您为回调指定了UseSynchronizationContext = false
,这意味着所有回调都在线程池上调用。UI不允许从任何线程更新自己,只有调度程序一个。因此,您需要将MessageLog
属性的更新封送到调度程序线程上。