C# 从子ViewModel到父ViewModel的属性返回值

C# 从子ViewModel到父ViewModel的属性返回值,c#,.net,wpf,mvvm,caliburn.micro,C#,.net,Wpf,Mvvm,Caliburn.micro,在我的WPF MVVM应用程序中,使用Caliburn.Micro,我有一个ViewModel,CreateServiceViewModel,点击一个按钮,就会在一个单独的窗口中打开一个GridView,供用户从中选择一行 我为此创建了另一个ViewModel,MemberSearchViewModel,它有两个属性: private Member selectedMember; public Member SelectedMember { get {

在我的WPF MVVM应用程序中,使用Caliburn.Micro,我有一个ViewModel,
CreateServiceViewModel
,点击一个按钮,就会在一个单独的窗口中打开一个GridView,供用户从中选择一行

我为此创建了另一个ViewModel,
MemberSearchViewModel
,它有两个属性:

    private Member selectedMember;

    public Member SelectedMember
    {
        get { return selectedMember; }
        set { selectedMember = value; }
    }

    private IList<Member> members;

    public IList<Member> Members
    {
        get { return members; }
        set { members = value; }
    }
private Member selectedMember;
公共成员选定成员
{
获取{return selectedMember;}
设置{selectedMember=value;}
}
IList私人成员;
公营机构成员
{
获取{返回成员;}
集合{members=value;}
}

如何将SelectedMember值返回调用ViewModel?该视图模型的属性为
服务。SelectedMember

一个选项是将
MemberSearchViewModel
存储为
CreateServiceViewModel
的字段,并定义
CreateServiceViewModel。SelectedMember
属性如下:

public Member SelectedMember
{
    get
    {
        return _memberSearchViewModel.SelectedMember;
    }
    set
    {
        _memberSearchViewModel.SelectedMember = value;
    }
}

一个选项是将
MemberSearchViewModel
存储为
CreateServiceViewModel
的字段,并定义
CreateServiceViewModel。SelectedMember
属性如下:

public Member SelectedMember
{
    get
    {
        return _memberSearchViewModel.SelectedMember;
    }
    set
    {
        _memberSearchViewModel.SelectedMember = value;
    }
}

一个选项是利用
NotifyPropertyChanged
。由于您使用的是ViewModels,因此它们很可能实现了
INotifyPropertyChanged
,您可以像框架一样使用它

当CreateServiceViewModel创建MemberSearchViewModel时,它将只订阅PropertyChanged事件:

//This goes wherever you create your child view model
var memberSearchViewModel = new MemberSearchViewModel(); //Or using a service locator, if applicable
memberSearchViewModel.PropertyChanged += OnMemberSearchPropertyChanged;

private void OnMemberSearchPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == "SelectedMember")
    {
        //Code to respond to a change in the Member
    }
}
然后在MemberSearchViewModel中,当用户从网格中选择成员时,只需引发NotifyPropertyChanged事件

编辑: 正如@DNH在注释中正确指出的,如果没有正确清理,使用这样的事件处理程序可能会导致内存泄漏。因此,当您完成MemberSearchViewModel时,请确保取消订阅
PropertyChanged
事件。例如,如果您只在用户选择成员之前需要它,您可以将其放入属性更改处理程序本身(我已将其切换为使用类级别变量来保存ViewModel):


一个选项是利用
NotifyPropertyChanged
。由于您使用的是ViewModels,因此它们很可能实现了
INotifyPropertyChanged
,您可以像框架一样使用它

当CreateServiceViewModel创建MemberSearchViewModel时,它将只订阅PropertyChanged事件:

//This goes wherever you create your child view model
var memberSearchViewModel = new MemberSearchViewModel(); //Or using a service locator, if applicable
memberSearchViewModel.PropertyChanged += OnMemberSearchPropertyChanged;

private void OnMemberSearchPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == "SelectedMember")
    {
        //Code to respond to a change in the Member
    }
}
然后在MemberSearchViewModel中,当用户从网格中选择成员时,只需引发NotifyPropertyChanged事件

编辑: 正如@DNH在注释中正确指出的,如果没有正确清理,使用这样的事件处理程序可能会导致内存泄漏。因此,当您完成MemberSearchViewModel时,请确保取消订阅
PropertyChanged
事件。例如,如果您只在用户选择成员之前需要它,您可以将其放入属性更改处理程序本身(我已将其切换为使用类级别变量来保存ViewModel):

怎么样

public interface INotifyMe<T>
{
    T ResultToNotify { get; set; }
}

public class CreateServiceViewModel : ViewModelBase, INotifyMe<Member>
{
    // implement the interface as you like...
}

public class MemberSearchViewModel : ViewModelBase
{
    public MemberSearchViewModel(INotifyMe<Member> toBeNotified)
    {
        // initialize field and so on...
    }
}
怎么样

public interface INotifyMe<T>
{
    T ResultToNotify { get; set; }
}

public class CreateServiceViewModel : ViewModelBase, INotifyMe<Member>
{
    // implement the interface as you like...
}

public class MemberSearchViewModel : ViewModelBase
{
    public MemberSearchViewModel(INotifyMe<Member> toBeNotified)
    {
        // initialize field and so on...
    }
}

作为我评论的后续,下面是一个使用
Prism
的示例-我从未使用过
Caliburn

创建事件-事件的有效负载将是您选择的成员:

public class YourEvent:CompositePresentationEvent<YourEventPayload>{}
public类YourEvent:CompositePresentationEvent{}
发布事件:

EventAggregator.GetEvent<YourEvent>().Publish(YourEventPayload);
EventAggregator.GetEvent<YourEvent>().Subscribe((i) => ...);
EventAggregator.GetEvent().Publish(YourEventPayload);
订阅活动:

EventAggregator.GetEvent<YourEvent>().Publish(YourEventPayload);
EventAggregator.GetEvent<YourEvent>().Subscribe((i) => ...);
EventAggregator.GetEvent().Subscribe((i)=>…);

作为我评论的后续,下面是一个使用
Prism
的示例-我从未使用过
Caliburn

创建事件-事件的有效负载将是您选择的成员:

public class YourEvent:CompositePresentationEvent<YourEventPayload>{}
public类YourEvent:CompositePresentationEvent{}
发布事件:

EventAggregator.GetEvent<YourEvent>().Publish(YourEventPayload);
EventAggregator.GetEvent<YourEvent>().Subscribe((i) => ...);
EventAggregator.GetEvent().Publish(YourEventPayload);
订阅活动:

EventAggregator.GetEvent<YourEvent>().Publish(YourEventPayload);
EventAggregator.GetEvent<YourEvent>().Subscribe((i) => ...);
EventAggregator.GetEvent().Subscribe((i)=>…);

事件聚合器是您可以使用的。。。我确信这是众多解决方案中的一个

public class MessageNotifier{
  public object Content{get;set;}
  public string Message {get;set;}
}


//MEF bits here
public class HelloWorldViewModel: Screen, IHandle<MessageNotifier>{
   private readonly IEventAggregator _eventAggregator

  //MEF constructor bits
  public YourViewModel(IEventAggregator eventAggregator){
    _eventAggregator = eventAggregator;
  }

   public override OnActivate(){
       _eventAggregator.Subscribe(this);
   }
   public override OnDeactivate(){
     _eventAggregator.UnSubscribe(this);
   }

   //I Handle all messages with this signature and if the message applies to me do something
   //
   public void Handle(MesssageNotifier _notifier){
        if(_notifier.Message == "NewSelectedItem"){
            //do something with the content of the selectedItem
            var x = _notifier.Content
        }
   } 
}

//MEF attrs
public class HelloWorld2ViewModel: Screen{
   private readonly IEventAggregator _eventAggregator
    //MEF attrs
    public HelloWorld2ViewModel(IEventAggregator eventAggregator){
       _eventAggregator = eventAggregator;
    }

    public someobject SelectedItem{
      get{ return _someobject ;}
      set{ _someobject = value;
          NotifyOfPropertyChange(()=>SelectedItem);
          _eventAggregator.Publish(new MessageNotifier(){ Content = SelectedItem, Message="NewSelectedItem"});
    }
}
公共类消息通知程序{
公共对象内容{get;set;}
公共字符串消息{get;set;}
}
//这里是MEF位
公共类HelloWorldViewModel:Screen,IHandle{
私有只读IEventAggregator\u事件聚合器
//MEF构造函数位
公共YourViewModel(IEventAggregator事件聚合器){
_eventAggregator=eventAggregator;
}
公共覆盖OnActivate(){
_eventAggregator.Subscribe(此);
}
公共覆盖OnDeactivate(){
_事件聚合器。取消订阅(此);
}
//我处理所有带有此签名的邮件,如果邮件适用于我,请执行某些操作
//
公共无效句柄(MessageNotifier\u notifier){
如果(_notifier.Message==“NewSelectedItem”){
//对selectedItem的内容执行一些操作
var x=\u notifier.Content
}
} 
}
//MEF吸引子
公共类HelloWorld2ViewModel:屏幕{
私有只读IEventAggregator\u事件聚合器
//MEF属性
公共HelloWorld2ViewModel(IEventAggregator事件聚合器){
_eventAggregator=eventAggregator;
}
公共someobject SelectedItem{
获取{return\u someobject;}
设置{u someobject=value;
NotifyOfPropertyChange(()=>SelectedItem);
_Publish(newmessagenotifier(){Content=SelectedItem,Message=“NewSelectedItem”});
}
}

EventAggregator是您可以使用的解决方案……我确信它是众多解决方案之一

public class MessageNotifier{
  public object Content{get;set;}
  public string Message {get;set;}
}


//MEF bits here
public class HelloWorldViewModel: Screen, IHandle<MessageNotifier>{
   private readonly IEventAggregator _eventAggregator

  //MEF constructor bits
  public YourViewModel(IEventAggregator eventAggregator){
    _eventAggregator = eventAggregator;
  }

   public override OnActivate(){
       _eventAggregator.Subscribe(this);
   }
   public override OnDeactivate(){
     _eventAggregator.UnSubscribe(this);
   }

   //I Handle all messages with this signature and if the message applies to me do something
   //
   public void Handle(MesssageNotifier _notifier){
        if(_notifier.Message == "NewSelectedItem"){
            //do something with the content of the selectedItem
            var x = _notifier.Content
        }
   } 
}

//MEF attrs
public class HelloWorld2ViewModel: Screen{
   private readonly IEventAggregator _eventAggregator
    //MEF attrs
    public HelloWorld2ViewModel(IEventAggregator eventAggregator){
       _eventAggregator = eventAggregator;
    }

    public someobject SelectedItem{
      get{ return _someobject ;}
      set{ _someobject = value;
          NotifyOfPropertyChange(()=>SelectedItem);
          _eventAggregator.Publish(new MessageNotifier(){ Content = SelectedItem, Message="NewSelectedItem"});
    }
}
公共类消息通知程序{
公共对象内容{get;set;}
公共字符串消息{get;set;}
}
//这里是MEF位
公共类HelloWorldViewModel:Screen,IHandle{
私有只读IEventAggregator\u事件聚合器
//MEF构造函数位
公共视图模式