从子视图模型返回属性到父ViewModel的值

时间:2013-05-16 14:25:39

标签: c# .net wpf mvvm caliburn.micro

在我的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; }
    }

如何将SelectedMember值恢复为调用ViewModel? ViewModel的属性为Service.SelectedMember

5 个答案:

答案 0 :(得分:2)

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"});
    }
}

答案 1 :(得分:1)

一种选择是利用NotifyPropertyChanged。由于您正在使用ViewModel,因此它们很可能实现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事件。因此,例如,如果您只需要它直到用户选择一个成员,您可以将其放入Property Changed Handler本身(我已将其切换为使用类级变量来保存ViewModel):

private void OnMemberSearchPropertyChanged(object sender, PropertyChangedEventArgs e)
{
    if(e.PropertyName == "SelectedMember")
    {
        //Code to respond to a change in the Member

        //Unsubscribe so the view model can be garbage collected
        _memberSearchViewModel.PropertyChanged -= OnMemberSearchPropertyChanged;
        _memberSearchViewModel = null;
    }
}

答案 2 :(得分:0)

一种选择是将MemberSearchViewModel存储为CreateServiceViewModel字段并定义CreateServiceViewModel.SelectedMember属性,如下所示:

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

答案 3 :(得分:0)

怎么样?

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...
    }
}

现在你可以让CreateServiceViewModel监听它自己的属性,你不必考虑删除事件监听器。

当然要做更经典的方式,或者使用像这样的界面。

public interface INotifyMe<T>
{
    void Notify(T result);
}

答案 4 :(得分:0)

作为评论的后续内容,以下是使用Prism的示例 - 我从未使用Caliburn

创建活动 - 活动的有效负载将是您的SelectedMember:

public class YourEvent:CompositePresentationEvent<YourEventPayload>{}

发布活动:

EventAggregator.GetEvent<YourEvent>().Publish(YourEventPayload);

订阅活动:

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