c# - 多个 WPF 控件使用的 WCF 双工服务

标签 c# .net wpf wcf mvvm

我正在开发一个 MVVM WPF 应用程序,它使用由服务器应用程序 (WPF) 托管的 WCF 服务。我对使用该服务的最佳方式有一些疑问:

    服务的
  1. InstanceContextMode 设置为 Single
  2. WCF 服务使用双工契约(Contract)和回调
  3. MainWindow 定期调用服务的“Ping”方法以了解(并以图标直观显示)服务是否可用。 MainWindow 实现了一个 PingReply 回调来获取回复。
  4. MainWindow 有一个Frame 用于加载不同的Pages。每个 Page 都包含多个 UserControls,它们调用该服务来更新它们的 View 。

这里是简化的服务接口(interface)ISrvService.cs

[ServiceContract(CallbackContract = typeof(ISrvServiceCallback))]
public interface ISrvService
{
    [OperationContract(IsOneWay = true)]
    void Ping();

    [OperationContract(IsOneWay = true)]
    void GetUserControlAStatus();

    [OperationContract(IsOneWay = true)]
    void GetUserControlBStatus();
}

public interface ISrvServiceCallback
{
    [OperationContract(IsOneWay = true)]
    void PingReply(string reply);

    [OperationContract(IsOneWay = true)]
    void GetUserControlAReply(string reply);

    [OperationContract(IsOneWay = true)]
    void GetUserControlAReply(string reply);
}

这样当我在MainWindow中实现ISrvServiceCallback接口(interface)有PingReply回调时,我还需要实现GetUserControlAReplyGetUserControlBReply(现在我只是在没有代码的情况下实现它们)

MainWindow.xaml.cs 中的 GetUserControlAReply

    public void GetUserControlAReply(string reply)
    {
        //nothing to do
    }

当我在 UserControlA 的模型中实现 ISrvServiceCallback 接口(interface)时,同样的事情发生了:我必须在没有代码的情况下实现 PingReply

我认为这不是一个好的工作方式。解决此类问题的最佳做法是什么?你能给我一些关于这种情况的教程吗?

编辑 正如@lokusking 所建议的,我提供了 UserControl 示例的模型和 View 模型。 View 绑定(bind)到 ViewModel 的 LblStatus

UserControlAModel.cs

public class UserControlAModel: INotifyPropertyChanged, SrvService.ISrvServiceCallback
{
    System.ServiceModel.InstanceContext instanceContext;
    SrvService.SrvServiceClient client;

    public event PropertyChangedEventHandler PropertyChanged;

    private string _Status;
    public string Status
    {
        get { return _Status; }
        set { _Status = value; NotifyPropertyChanged(); }
    }

    public UserControlAModel()
    {
        Status = "NOT CONNECTED";
    }

    public void GetStatus()
    {
        instanceContext = new System.ServiceModel.InstanceContext(this);
        client = new SrvService.SrvServiceClient(instanceContext);
        client.GetUserControlAStatus();
    }

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }

    //callbacks implementation
    public void GetUserControlAReply(string reply)
    {
        Status = reply;
    }

    public void GetUserControlBReply(string reply)
    {
        //nothing to do
    }

    public void PingReply(string reply)
    {
        //nothing to do
    }
}

UserControlAViewModel.cs

public class UserControlAViewModel : INotifyPropertyChanged
{
    private UserControlAModel _uControlAModel;
    public UserControlAModel MyUserControlAModel
    {
        get
        { return _uControlAModel; }
        set
        { _uControlAModel = value; NotifyPropertyChanged(); }
    }

    public string LblStatus
    {
        get { return MyUserControlAModel.Status; }
        set { MyUserControlAModel.Status = value; NotifyPropertyChanged(); }
    }

    public UserControlAViewModel()
    {
        MyUserControlAModel = new UserControlAModel();
        MyUserControlAModel.PropertyChanged -= UserControlAModel_PropertyChanged;
        MyUserControlAModel.PropertyChanged += UserControlAModel_PropertyChanged;

        MyUserControlAModel.GetStatus();
    }

    private void UserControlAModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
    {
        NotifyPropertyChanged(string.Empty);
    }

    public event PropertyChangedEventHandler PropertyChanged;

    private void NotifyPropertyChanged([CallerMemberName] string propertyName = null)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

最佳答案

创建一个单独的类来实现您的 ISrvService

下一步让这个类成为单例类。 现在您可以在任何地方访问您的 wcf 函数并且只有一个实现。

编辑:这是一个基于我之前代码的解决方案。

实现

public class SrvServiceCallbackProxy : ISrvServiceCallback
  {

    public event EventHandler PingReplyReceived;

    private SrvServiceClient _innerClient;

    private SrvServiceCallbackProxy() {
      var instanceContext = new System.ServiceModel.InstanceContext(this);
      _innerClient = new SrvService.SrvServiceClient(instanceContext);

    }

    private static SrvServiceCallbackProxy _instance;
    public static SrvServiceCallbackProxy Instance => _instance ?? (_instance = new SrvServiceCallbackProxy());


    public void PingReply(string reply) {
      this.PingReplyReceived?.Invoke(reply, EventArgs.Empty);
    }
}

用法

SrvServiceCallbackProxy.Instance.PingReplyReceived += ..Here goes the method..

注意

我一直在这样做。我将我的回调实现包装在 Singleton-Proxy 隧道服务器响应事件中。

好处: 你有一个!始终可用的类。 您只需实现一次您的逻辑! 每个消费者都会收到您可以按需订阅的事件的通知。

关于c# - 多个 WPF 控件使用的 WCF 双工服务,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37961935/

相关文章:

c# - 单击按钮时下拉组合框

c# - LINQ to SQL 类,如何更改列格式? (数据网格)

c# - 如何在 ListCollectionView 中进行搜索?

c# - .NET Xml 反序列化,xsi :type attribute 的问题/错误

c# - 抛出 'System.Windows.Forms.AxHost+InvalidActiveXStateException' 类型的异常

c# - 我如何在 wpf 中为组合框的选定项目编写项目模板

c# - 如何在 WPF 中强制显示工具提示

c# - 自定义 JSON 序列化以节省传输的数据

c# - 有没有办法逐行阅读word文档

.net - IQueryable IGrouping如何工作