Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/joomla/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 多个WPF控件使用的WCF双工服务_C#_.net_Wpf_Wcf_Mvvm - Fatal编程技术网

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

C# 多个WPF控件使用的WCF双工服务,c#,.net,wpf,wcf,mvvm,C#,.net,Wpf,Wcf,Mvvm,我正在开发一个使用服务器应用程序(WPF)托管的WCF服务的MVVM WPF应用程序。我对使用该服务的最佳方式有一些疑问,因为我知道: 服务的InstanceContextMode设置为Single WCF服务使用带有回调的双工协定 主窗口定期调用服务的“Ping”方法,以了解(并以图标直观显示)服务是否可用。MainWindow实现PingReply回调以获取回复 主窗口有一个用于加载不同页面的框架。每个页面都包含几个用户控件,这些控件调用服务来更新其视图 这是简化的服务接口ISrvServi

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

  • 服务的InstanceContextMode设置为Single
  • WCF服务使用带有回调的双工协定
  • 主窗口定期调用服务的“Ping”方法,以了解(并以图标直观显示)服务是否可用。MainWindow实现PingReply回调以获取回复
  • 主窗口有一个用于加载不同页面的框架。每个页面都包含几个用户控件,这些控件调用服务来更新其视图
  • 这是简化的服务接口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);
    }
    
        public void GetUserControlAReply(string reply)
        {
            //nothing to do
        }
    
    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
        }
    }
    
    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));
        }
    }
    
    这样,当我在MainWindow中实现ISrvServiceCallback接口以实现PingReply回调时,我还需要实现GetUserControlAReply和GetUserControlBReply(现在我只是实现它们,没有代码)

    GetUserControlAReply在main window.xaml.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);
    }
    
        public void GetUserControlAReply(string reply)
        {
            //nothing to do
        }
    
    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
        }
    }
    
    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));
        }
    }
    
    在UserControlA模型中实现ISrvServiceCallback接口时也会发生同样的情况:我必须在没有代码的情况下实现PingReply

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

    编辑 正如@lokusking所建议的,我提供了UserControl示例的Model和ViewModel。视图绑定到ViewModel的LblStatus

    UserControlAModel.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);
    }
    
        public void GetUserControlAReply(string reply)
        {
            //nothing to do
        }
    
    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
        }
    }
    
    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));
        }
    }
    
    UserControlAViewModel.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);
    }
    
        public void GetUserControlAReply(string reply)
        {
            //nothing to do
        }
    
    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
        }
    }
    
    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..
    
    注意

    我一直在这样做。我将回调实现包装在带有事件的单例代理隧道服务器响应中

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

    我的错误:我是指客户端的ISrvServiceCallback接口这里的答案相同;)这个解决方案适用于这两个方面,我认为我遗漏了一些东西:UserControlA是由绑定到UserControlAViewModel的UserControlAView.xaml形成的,其中包括UserControlAModel。现在,模型调用服务并实现回调以更新内部属性(向viewModel bla bla发送通知)。如何从包含回调代码的实现中修改UserControlAModel的属性?@aDone您可以编辑您的问题并粘贴代码,以便我可以更深入地查看吗?很好的建议!问题编辑!我将试用您上次编辑的代码,看看会发生什么!:)我会让你知道的!