使用ICommand和ServiceLocator以MVVM的方式传递Parent对象以加载Child对象

本文关键字:对象 Parent Child 方式传 加载 ICommand ServiceLocator MVVM 使用 | 更新日期: 2023-09-27 18:25:47

我正在使用MVVMLight工具包创建一个WPF应用程序。我有一个"父"窗体(ParentView),希望通过传递将加载所有"子"对象的"父"对象(parent)来加载"子"窗体(ChildView)。

我已经包含了我认为在任何人的分析中都很重要的3个主要类的代码片段:ViewModelLocator、ChildViewModel、ParentViewModel。我最初想通过实例化ParentView(见下文)在ParentViewModel中实现ICommand属性,但这似乎不正确,因为我试图用MVVM的方式来实现这一点。有人能为以下当前结构提供帮助吗?以及我如何将父母传给孩子?

// ----- ChildViewModel -----
public class ChildViewModel
{
  // this ctor doesn't make sense in the MVVM world, right?...
  public ChildViewModel(Parent selectedParent)
  {
     this.Parent = selectedParent;
     // ...
  }
  // how do I plug into this one?...
  public ChildViewModel(IParentService parentService)
  {
     this.ParentService = parentService
     // ...
  }
  // ... removed other code for brevity
}
// ----- ParentViewModel -----
{
  public ICommand ShowChildCommand
  {
     get { return new RelayCommand(() => new ChildView(SelectedParent).Show()); }
  }
  // ... removed other code for brevity
}
// ----- ViewModelLocator -----
public class ViewModelLocator
{
  public ChildModel ChildViewModel
  {
     get { return ServiceLocator.Current.GetInstance<ChildViewModel>(); } 
  }
  public ParentModel ParentViewModel
  {
     get { return ServiceLocator.Current.GetInstance<ParentViewModel>(); } 
  }
  public ViewModelLocator()
  {
      SimpleIoc.Default.Register<IChildService, ChildService>();
      SimpleIoc.Default.Register<IParentService, ParentService>();
      // ... removed other code for brevity
      SimpleIoc.Default.Register<ChildViewModel>();
      SimpleIoc.Default.Register<ParentViewModel>();
  }
  // ... removed other code for brevity
}

//------第2次修订----------------

我采纳了用户@kidshaw的最新建议,但我被不得不在ParentView中创建ChildView实例的评论难住了。我不知道该怎么做。我再次阅读了MSDN上关于信使的文章,但不知道它如何帮助我解决这个问题。我已经包含了以下最新代码。请参考评论部分。

public class ParentViewModel
{
 public ICommand ShowChildCommand
  {
      get { return new RelayCommand(OnLoadChildCommand); }
  }
 private void OnLoadChildCommand()
  {
     Messenger.Default.Send(new ParentToChildMessage { Parent = this.CurrentParent });
     // ****** this is where I instantiated the child view
     // I am sure this is wrong...
     var view = new ChildView().Show();
  }
 public class ParentToChildMessage : MessageBase
  {
      public Parent Parent { get; set; }
  }
...
}

ChildViewModel看起来像:

public class ChildViewModel
{
  public ChildViewModel(IChildService service)
        {
            this.ServiceProxy = service;
            this.MessengerInstance.Register<ParentViewModel.ParentToChildMessage>(this, this.OnParentToChildMessage);
            this.ChildCollection = new ObservableCollection<Child>();
            GetChildInfo(this.CurrentParent);
        }
}

使用ICommand和ServiceLocator以MVVM的方式传递Parent对象以加载Child对象

在您的示例中,它表明ViewModel正在与视图对话。如果您已经跳转到MVVM模式,则可以避免这种情况。

我希望使用MVVM光中的消息框架来实现这一点。您可以通过这种方式将父视图和子视图分开,并在不将两者耦合在一起的情况下传递数据。您可以在子视图模型中控制子视图的可见性,并在消息处理程序中进行切换。

这篇msdn文章将介绍这些概念。http://msdn.microsoft.com/en-us/magazine/dn745866.aspx.

根据您的编辑

第一个基本步骤是创建一个消息类,将数据从父级传递到子级。

public class ParentToChildMessage : MessageBase
{
    /// Include any properties you want to send
}

如果没有要传递的数据,可以使用GenericMessage<>对象来传递bool,为自己节省一些代码。然而,消息是按类型注册的,所以使用泛型意味着您的注册方法将需要进行更多的检查——我稍后会展示他的。

在父视图模型中,您有一个命令ShowChildCommand,我们可以将其用作发送消息的点。

public class ParentViewModel : ViewModelBase
{
    public ParentViewModel()
    {
    }
    public ICommand ShowChildCommand
    {
        get
        {
            return new RelayCommand(()=>this.MessengerInstance.Send<ParentToChildMessage>(new ParentToChildMessage()));
        }
    }
}

父视图模型就是这样。接下来,我们在子视图模型中注册一个消息接收器。

public class ChildViewModel : ViewModelBase
{
    public ChildViewModel()
    {
        this.MessengerInstance.Register<ParentToChildMessage>(this, this.OnParentToChildMessage);
    }
    private void OnParentToChildMessage(ParentToChildMessage obj)
    {
        // Inspect obj to decide what to do - let's just set as visible
        this.IsVisible = true;
    }
    public bool IsVisible
    {
        get
        {
            return _IsVisible;
        }
        set
        {
            if (value != _IsVisible)
            {
                _IsVisible = value;
                RaisePropertyChanged();
            }
        }
    }
    private bool _IsVisible;
}

您可以在这里看到,在构造函数中,我们向强类型注册了一条消息。如果我们使用泛型,则OnParentToChildMessage的主体必须区分此消息和其他可能的相同类型的消息——这不是很好的代码,尤其是随着时间的推移,您可能会构建多个消息交互。

子视图模型会更新一个简单的bool IsVisible属性-要使其工作,父视图中需要有一个子视图的实例。这将确保创建您的子视图和子视图模型的实例。

我希望这能有所帮助。