【问题标题】:Using ICommand and ServiceLocator to pass Parent object to load Child objects in an MVVM way使用 ICommand 和 ServiceLocator 传递 Parent 对象以 MVVM 方式加载 Child 对象
【发布时间】:2014-10-06 18:47:56
【问题描述】:

我正在使用 MVVMLight 工具包创建 WPF 应用程序。我有一个“父”表单(ParentView)并且想通过传递将加载所有“子”对象的“父”对象(Parent)来加载一个“子”表单(ChildView)。

我已经包含了 3 个我认为在任何人的分析中都很重要的主要类的代码 sn-ps: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
}

// ------ REVISION 2 EDITS ------------

我采纳了用户@kidshaw 的最新建议,但我被评论难住了,其中我必须在 ParentView 中创建 ChildView 的实例。我不知道该怎么做。我再次阅读了有关 Messenger 的 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);
        }
}

【问题讨论】:

  • 在你的父视图中创建一个子视图实例。查看是 xaml。我建议您将子控件的实例添加到父控件,以便同时实例化。

标签: c# wpf mvvm mvvm-light icommand


【解决方案1】:

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

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

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

根据您的编辑...

第一个基本步骤是创建一个消息类以将您的数据从父级传输到子级。

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

如果您没有要传递的数据,您可以使用 MVVM Light 中的 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 属性 - 要使其正常工作,您的父视图将需要在其中包含子视图的实例。这将确保创建您的子视图,以及您的子视图模型的实例。

我希望这会有所帮助。

【讨论】:

  • #kidshaw:我将看看信使概念,因为我目前没有使用 MVVMLight 工具包的那部分。您希望查看我的代码的哪一部分?
  • 我继续编辑了我的原始帖子,并添加了一些希望有所帮助的代码 sn-ps。
  • @user118190,我觉得我给出的答案有点简短,所以如果有更多代码,我可以给你一个例子。如果您乐于自己研究这个概念,请随意。您使用 ViewModelLocator 的事实表明您非常有能力 :) 从您提供的额外代码中,我将在今天晚些时候用一个示例更新我的答案。
  • 确实感谢您的帮助。我仍在攻击这个问题,但没有任何运气。我期待着您可以发送给我的任何提示。
  • @user118910 我认为编辑应该涵盖基础知识
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-03-22
  • 2018-03-12
  • 2012-01-23
  • 2011-07-23
相关资源
最近更新 更多