【问题标题】:Updating a viewmodel from another viewmodel从另一个视图模型更新视图模型
【发布时间】:2011-08-09 14:50:07
【问题描述】:

我有两个 ViewModel,一个附加到主窗口,另一个附加到通过单击主窗口上的按钮打开的子窗口。子窗口包含一个项目列表,我想选择一个项目并通过更新主窗口视图模型将其显示在主窗口中。实现这一目标的最佳方法是什么。谢谢!

【问题讨论】:

  • 您专门要求一种“最佳”方式来执行此操作。什么对你来说是“最好的”?它可能意味着最快、最简单、最容易理解/调试、最少代码等。
  • 最简单是非常主观的,但我倾向于主要基于对象之间真实关系的概念模型。如果他们是父/子,直接引用可能非常直接。
  • 在这种情况下,“最好”对我来说意味着最简单的方法,因为我对 wpf 和 mvvm 非常陌生。
  • 我编辑了我的答案,以最简单的方式列出了我个人选择的“最佳”。

标签: c# wpf mvvm viewmodel


【解决方案1】:

我认为在两个视图模型之间传递消息的最佳方式是事件编程。

【讨论】:

    【解决方案2】:

    有很多方法可以做到这一点。

    • 将对主视图模型/父视图模型的引用传递给子视图模型,并让子视图模型调用主视图模型。

    • 让子视图模型触发父订阅的事件。

    • 使用信使/中介在两者之间进行通信。父母订阅,孩子发布消息。这提供了松散耦合。

    • 将主视图模型设置为全局服务。以某种方式注册它。让孩子查找服务(需要全局服务是一个很常见的问题),然后在全局/通用接口上调用一些东西。

    根据我的经验,最简单的方法是 #2。在子视图模型上定义一个事件。父级必须查找子级(我不知道它是否包含它或您的视图模型是如何构造的)并订阅该事件。

    【讨论】:

    • 这些方法中的任何一种都可能是合适的。这在很大程度上取决于上下文。除非虚拟机在概念上密切相关,否则耦合是不合适的。
    • 非常有用的答案,我的 MainViewModel 类开始看起来一团糟。谢谢
    【解决方案3】:

    几天前我也遇到了同样的问题;-)

    最后,我使用了一个中介来传达两个视图模型。事实上,我使用了 MVVM Light 的 Messenger。

    public void Search(object parameter)
            {
                ChildWindow window = new ChildWindow();
    
                SearchWindow pageSearch = new SearchWindow();
    
                window.Content = pageSearch;
                window.Show();
    
                Messenger.Default.Register<Messages.CloseWindowMessage>(this, action => this.closeWindow(action));
            }
    

    之后,我用我需要从主窗口了解的所有内容定义了 Message:

    public class CloseWindowMessage : MessageBase
        {
            public bool Result { get; set; }
            public Model.Selected Selected { get; set; }
        }
    

    最后从子窗口返回的消息你只需要注册带有结果的消息和你想要返回的对象。

    您应该从视图的代码隐藏中注册以关闭窗口。

    【讨论】:

    • 您能否完成您的示例,然后我可以使用它。您在哪里使用过这种搜索方法?如何从 ViewModel 注册。可以通过消息发送什么?例如,如果我需要来自第二个 VM 的变量,我如何才能在第一个 VM 中访问它?谢谢。
    【解决方案4】:

    在 ViewModel 之间进行通信的标准方式是使用某种消息传递。一个很好的实现是MVVM Light Toolkit

    这里有一些(随机的)代码,使用了其中的默认信使:

    //Registering:
    Messenger.Default.Register<IEnumerable<BookViewModel>>(this, true, fillSourceWith);
    Messenger.Default.Register<DisplayModeEnum>(this, ChangeMainTemplates);
    //with a specific "token"
    Messenger.Default.Register<object>(this, MessageTokens.ClearList, o => BookSource.Clear()); 
    
    //Sending
    Messenger.Default.Send<List<BookViewModel>>(newBooks);
    Messenger.Default.Send<DisplayModeEnum>(DisplayModeEnum.MediumLayout);
    Messenger.Default.Send<object>(null, MessageTokens.ClearList);
    

    【讨论】:

    • -1。他在谈论父母/孩子的关系。在这里发消息不是个好主意。
    • 我认为这里的消息传递应该没问题。如果没有消息,您将不得不以某种方式耦合您的视图模型。
    • 消息传递可能合适,也可能不合适。这个问题可能太复杂了,但它是一个很好的解决方案。
    • @Josh G - 我同意。根据他的情况,还有其他方法可能同样有效。为向他人展示您的答案 +1
    • 他要求“最佳”解决方案,但“最佳”非常主观,需要更多关于他的上下文的信息。
    【解决方案5】:

    最好的方法是让子级对父级有某种引用,并在关闭子级时更新此父级。

    或者你可以对孩子进行某种事件,让父母监听这个事件。然后在孩子关闭时引发此事件。

    当两个 ViewModel 在逻辑上不相关时使用消息传递。

    [咆哮]人们甚至不知道OOP的基本原理还是什么? [/咆哮]

    【讨论】:

    • 我认为在这种情况下使用信使不一定是糟糕的设计。这取决于许多因素,但发送一个简单的消息可能比在两个 VM 之间建立 OO 关系更简单、更有效
    • 我认为问题在于没有最佳实践方法可以将其作为 MVVM 模式的一部分。
    猜你喜欢
    • 1970-01-01
    • 2019-01-23
    • 2017-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-28
    • 2017-02-06
    相关资源
    最近更新 更多