MVVM Light & WPF - 将窗口的多个实例绑定到 ViewModel

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/16993433/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-13 08:57:47  来源:igfitidea点击:

MVVM Light & WPF - Binding Multiple instances of a Window to a ViewModel

c#wpfmvvmmvvm-light

提问by Jason D

I am working on my first project in MVVM and I've chosen to use the MVVM Light Toolkit. I have a GameViewModelthat handles business on the main screen of my game. I need to find out how to open a new window (AdventurerView) with an instance of Adventureras a parameter when a command is executed, have it bound to AdventurerViewModel, and display and return data. Instances of this window will be opened and closed frequently. I have been stuck on this for a couple of days now and it's driving me crazy. I would like to learn how to do this in an MVVM-friendly way, preferably with the tools provided by MVVM Light or pure XAML.

我正在 MVVM 中开展我的第一个项目,并且我选择使用 MVVM Light Toolkit。我有一个GameViewModel在我游戏的主屏幕上处理业务的。我需要找出如何在执行命令时AdventurerView以 的实例Adventurer作为参数打开一个新窗口 ( ) ,将其绑定到AdventurerViewModel,并显示和返回数据。此窗口的实例将经常打开和关闭。我已经坚持了几天了,这让我发疯了。我想学习如何以对 MVVM 友好的方式执行此操作,最好使用 MVVM Light 或纯 XAML 提供的工具。

I've tried using MVVM Light's ViewModelLocatorbut since AdventurerViewis a window it won't work; it says "Can't put a Window in a Style", though the program still compiles and runs. Could there be something I could change to make that work? Or is there another way to bind them in XAML? Or another approach entirely? I would really love to be able to move on from this. I have also tried using MVVM Light's messenger to no avail (which still doesn't tackle the View/ViewModel issue).

我试过使用 MVVM Light 的,ViewModelLocator但由于AdventurerView是一个窗口,它不起作用;它说“不能把窗口放在一个样式中”,尽管程序仍然可以编译和运行。有什么我可以改变的东西吗?还是有另一种方法可以在 XAML 中绑定它们?或者完全是另一种方法?我真的很想能够继续前进。我也尝试过使用 MVVM Light 的 Messenger 无济于事(它仍然没有解决 View/ViewModel 问题)。

I just need to be able to create a window that is bound to AdventurerViewModeland display/return the appropriate data.

我只需要能够创建一个绑定到AdventurerViewModel并显示/返回适当数据的窗口。

AdventurerView.xaml is in its default state at the moment, but I feel that if I could bind the appropriate data that might help (DataContext).

AdventurerView.xaml 目前处于默认状态,但我觉得如果我可以绑定可能有帮助的适当数据 (DataContext)。

AdventurerViewModel is pretty bare-bones as well

AdventurerViewModel 也很简单

class AdventurerViewModel : ViewModelBase
{
    #region Members

    private Adventurer _adv;

    #endregion

    #region Properties

    public Adventurer Adv
    {
        get { return _adv; }
        set { _adv = value; }
    }

    #endregion

    #region Construction

    public AdventurerViewModel(Adventurer adv)
    {
        this._adv = adv;
    }

    #endregion
}

App.xaml with the non-working DataTemplate at the bottom:

App.xaml 与底部的非工作 DataTemplate:

<Application StartupUri="MainWindow.xaml"
         xmlns:views="clr-namespace:AoW.Views"
         xmlns:vm="clr-namespace:AoW.ViewModels" 
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         x:Class="AoW.App" 
         xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
         mc:Ignorable="d">

<Application.Resources>
    <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" />

    <DataTemplate DataType="{x:Type vm:GameViewModel}">
        <views:GameView />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:TitleViewModel}">
        <views:TitleView />
    </DataTemplate>
    <DataTemplate DataType="{x:Type vm:AdventurerViewModel}">
        <views:AdventurerView />
    </DataTemplate>

</Application.Resources>
</Application>

The command in GameViewModelthat will hopefully make this all happen (the messagebox just confirms that the command is firing):

其中的命令GameViewModel有望使这一切发生(消息框只是确认命令正在触发):

    private void ExecuteShowAdvCommand(Adventurer adv)
    {
        System.Windows.MessageBox.Show(adv.Name);
    }

I don't really know what else to include.

我真的不知道还要包括什么。

回答by Viv

Ok I put together a demo that should make this hopefully easier for you Download Link

好的,我整理了一个演示,希望可以让您更轻松下载链接

Functionality:

功能:

  • 3 Windows in Total (MainWindow, ModalWindow, NonModalWindow)
  • MainWindowhas a TextBoxyou can type whatever you want into.
  • 2 buttons on the top will open the Modal / NonModal Window accordingly
  • Each window when opened will display the message that was in MainWindow's TextBoxin a TextBlockinside them.
  • In each window you can tick a CheckBoxto update the value in result's textblock in MainWindow(For the Modal Window this will kick in when modal window is closed. For NonModal changes can be seen asap)
  • 总共 3 个窗口 ( MainWindow, ModalWindow, NonModalWindow)
  • MainWindow有一个TextBox你可以输入任何你想要的。
  • 顶部的 2 个按钮将相应地打开模态/非模态窗口
  • 打开会显示在主窗口的消息时,每个窗口都TextBoxTextBlock里面他们。
  • 在每个窗口中,您可以勾选 aCheckBox以更新结果文本块中的值MainWindow(对于模态窗口,这将在模态窗口关闭时启动。对于非模态更改可以尽快看到)

That's it for functionality,

这就是功能性,

Concepts:

概念:

  • Registering Multiple VM's with the SimpleIoCand using GetInstance(...)to request them out.
  • Messenger class usage with a custom message type OpenWindowMessage
  • Opening Modal / Non Modal Windows from a parent VM staying true to the MVVM principles
  • Passing data between windows(just shown in NonModal)
  • 向 注册多个 VMSimpleIoC并使用它GetInstance(...)来请求它们。
  • 使用自定义消息类型的 Messenger 类 OpenWindowMessage
  • 从父虚拟机打开模态/非模态窗口,遵循 MVVM 原则
  • 在窗口之间传递数据(仅在 NonModal 中显示)

Important Note:- The method used in this example to set the non DP DialogResultfrom the modal window is not MVVM friendly cos it uses code-behind to set the DialogResultproperty on a Window.Closingevent which shouldbe avoided(If needing to be "testable"). My preferred approach is a bit long and is very well documented HERE(Mixture of question and answer). Hence why I ignored it for the sake of this sample.

重要说明:- 本示例中用于DialogResult从模态窗口设置非 DP的方法不是 MVVM 友好的,因为它使用代码隐藏来设置避免DialogResultWindow.Closing事件的属性(如果需要“可测试”)。我的首选方法有点长,这里有很好的记录(问答混合)。因此,为什么我为了这个样本而忽略了它。

回答by srock

Follow up to Viv, I modified the sample to include an example of opening the window without using a code behind.

跟进 Viv,我修改了示例以包含一个在不使用隐藏代码的情况下打开窗口的示例。

Sample project is here.

示例项目在这里。

I'm utilizing the ViewModelLocator singleton with a static method that news up the viewmodel and window and Data Context instead of the code behind.

我将 ViewModelLocator 单例与静态方法一起使用,该方法更新视图模型和窗口以及数据上下文,而不是后面的代码。

Blog Post with Details.Let me know which method is preferable. I dislike using code behind, but there could be pro's and con's I'm missing.

包含详细信息的博客文章。让我知道哪种方法更可取。我不喜欢使用隐藏的代码,但可能有我遗漏的优点和缺点。