【问题标题】:Getting a value from a child WPF window that has a seperate viewmodel using the MVVM pattern使用 MVVM 模式从具有单独视图模型的子 WPF 窗口中获取值
【发布时间】:2015-06-23 04:53:12
【问题描述】:

我在我的第一个 MVVM WPF 应用程序上取得了相当大的进展,我现在遇到的问题是我有一个具有视图模型的窗口。
此窗口有一个按钮,可以打开另一个具有另一个视图模型的窗口。 想象第一个窗口上有一个文本框。
打开第二个窗口后,用户将选择一个值并单击保存,此窗口将关闭并使用其值更新第一个窗口。
推送保存时,我在调用 SaveMethod 的 childwindows Viewmodel 上有一个 ICommand。我将选定的值存储在子窗口视图模型的属性中。

但是如何使用此值更新主窗口文本框?我想我在主窗口视图模型上绑定了一个属性,但不确定如何继续。

请指教,如果需要,我可以提供代码示例,但我想我可能已经解释得很好了,
哦,感谢 StackOverflow 的每个人对我的问题的帮助,我学到了很多东西。

【问题讨论】:

  • 请分享一些你迄今为止尝试过的代码。
  • 您确实需要显示一些代码才能让任何人帮助您
  • 子窗口是模态对话框吗?这意味着您需要关闭对话框才能继续在父窗口中工作。大多数情况下,情况就是这样。我在这里写了一个在 mvvm 中使用对话框的示例:stackoverflow.com/questions/501886/…。它演示了登录窗口弹出,其中父窗口的视图模型访问子虚拟机

标签: c# wpf xaml mvvm


【解决方案1】:

使用 MVVM Light 框架非常简单。出于演示的目的,我将使用字符串作为您要传递的值,但很容易为您需要传递的任何内容构造不同的消息类型。

在您的第一个 Window 的 ViewModel 的构造函数中,您注册以接收 NotificationMessages。 NotificationMessages 用于发送字符串消息:

public MyFirstViewModel()
{
    Messenger.Default.Register<NotificationMessage>(this, NotificationMessageReceived);
}

在第二个 Window 的 ViewModel 中的 SaveMethod 中,您发送一条带有您想要传递的值的消息。我使用MyStringValue 作为存储用户在第二个窗口中选择的值的属性的名称:

private void SaveMethod()
{
    MessengerInstance.Send(new NotificationMessage(MyStringValue));
}

当第一个窗口的 ViewModel 接收到该消息时,将调用 NoitificationMessageReceived 方法。我将把该值放在第一个 ViewModel 上的字符串属性中,名为 MySavedValue

private void NotificationMessageReceived(NotificationMessage msg)
{
    MySavedValue = msg.Notification;
}

在第一个窗口的视图中,您有一个 TextBox,其 Text 属性绑定到 MySavedValue。每当更新 MySavedValue 时都会更新。

【讨论】:

  • 谢谢,MessengerInstance 是什么?我找不到这个
  • MessengerInstance 是来自 MVVM Light 框架的 Messenger 类的一部分。添加必要引用的最简单方法是使用 ID 为“MVVM Light”的 Nuget。添加引用时要小心 - 框架在您的项目中放置了一些新项目,包括一个名为“MainViewModel”的 ViewModel。如果你已经有一个叫做 MainViewModel 的东西,那么不要用新的复制它。之后有几个相当琐碎的注册工作要做,你应该启动并运行。这里有很多信息:blog.galasoft.ch/posts
  • 感谢您的帮助,我已经添加了 MVVM Light Framework,但仍然找不到 MessengerInstance。但它确实有 Messenger.Default?
  • 我在命名空间 Galasoft.MvvmLight 中有它。你有'使用 Galasoft.MvvmLight;'声明?
  • 我将其更改为 Messenger.Default.Send 并且效果很好,谢谢
【解决方案2】:

在父视图模型中,您需要对子视图模型的引用。当子窗口关闭时,您需要获取第二个视图模型的属性值并将其设置为第一个父视图模型的适当属性。

【讨论】:

    【解决方案3】:

    一种可行(且简单)的解决方案是为两个窗口保留一个 ViewModel

    <Grid>
        <StackPanel>
            <TextBox Text="{Binding TheText}" />
            <Button Command="{Binding ShowOptionsCommand}" Content="..."/>
        </StackPanel>
        <Popup IsOpen="{Binding IsShowingOptions}">
            <StackPanel>
                <ListBox ItemsSource="{Binding Options}" 
                        SelectedItem="{Binding SelectedOption,Mode=TwoWay}"/>
                <Button Command="{Binding SaveOption}">Save</Button>
            </StackPanel>
        </Popup>
    </Grid>
    
    //ShowOptionsCommand handler
    void ShowOptions() 
    {
        IsShowingOptions = true;
    }
    //SaveOptionCommand handler
    void SaveOption() 
    {
        TheText = SelectedOption;
        IsShowingOptions = false;
    }
    

    我正在使用 Popup 来简化示例。

    【讨论】:

      【解决方案4】:

      我个人会使用已经提到的 mvvm light 框架,但另一种选择是利用 IOC,也包含在上述框架中。

      在这种模式下,视图模型具有接口,并作为来自视图模型定位器数据源的属性绑定。其中,子视图模型可以注入到父视图模型中。因为 IOC 可以创建对象的单例实例,所以将相同的实例提供给父窗口,就像绑定到子窗口一样。这样您就可以通过一个接口获得对视图模型的引用,从而保持分离。

      仅将其作为已提供的替代技术解决方案提供。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2018-04-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多