【问题标题】:Property in ViewModel not displayed in ViewViewModel 中的属性未显示在 View 中
【发布时间】:2011-09-14 12:31:22
【问题描述】:

我有一个名为 MainWindowViewModel 的 ViewModel。在这个我有一个属性,当发生错误时显示一个模式窗口。只要在启动过程中发生错误,它就可以正常工作。

当启动后出现错误时,在 SubViewModel 中,我调用 MainWindowViewModel 中的参数化构造函数。

MainWindowViewModel.cs

public MainWindowViewModel()
{
    if (!isServerRunning)
    {
        this.ModalWindow = new LogViewModel("Server is down.");
    }
    else
    {
        this.ModalWindow = new LogViewModel();
    }
}


public MainWindowViewModel(string logMessage)
{
    this.ModalWindow = new LogViewModel(logMessage);
}


public LogViewModel ModalWindow
{
    get
    {
        return _modalWindow;
    }
    set
    {
        _modalWindow = value;

        OnPropertyChanged("ModalWindow");
     }
}

MainWindow.xaml

....

<Grid>
    <vw:LogView Content="{Binding Path=ModalWindow}"/>
</Grid>
  • MainWindowViewModel 绑定到 MainWindow.xaml

  • SubViewModel 绑定到 SubView.xaml

  • MainWindow.xaml 加载多个视图,其中之一是 SubView。

App.xaml 中,我创建了一个 ViewModel 实例并将其绑定到 MainWindow。

protected override void OnStartup(StartupEventArgs e)
{                                  
    base.OnStartup(e);
    MainWindow mainWindow = new MainWindow();
    MainWindowViewModel viewModel = new MainWindowViewModel();
    mainWindow.DataContext = viewModel;
    mainWindow.Show();
}

我意识到,如果我在 SubViewModel 中创建模态窗口属性并将其绑定到 SubView,则在启动后发生错误时会显示模态窗口。但这不行,因为 SubView 只是一个覆盖 MainWindow 1/4 的 DockPanel。 IE。 1/4 只覆盖了一个模态窗口,而不是整个 MainWindow。

当我从 SubViewModel 调用参数化构造函数时,我不确定为什么模式窗口没有出现在 MainWindow 中。当我调试时,我看到_modalWindow = value; 部分具有正确的值,但无论如何模式窗口都不会显示。

我将 ViewModel 绑定到 MainWindow 的 Datacontext。这可能就是为什么我在启动时出现错误时看到模态窗口的原因。对于启动后的错误:我(从我在 MainWindowViewModel 中调用参数化构造函数的 SubViewModel)是否必须再次对 Mainwindow 的数据上下文进行某种绑定?在不必创建 MainWindow 的新实例的情况下,最好的方法是什么?因为 MainWindow 应该只创建一次。

非常感谢任何帮助。

【问题讨论】:

    标签: c# wpf data-binding mvvm datacontext


    【解决方案1】:

    看起来您每次发生错误时都在重新创建 ViewModel。如果是这样,您还需要在视图中重置绑定,这将违背 MVVM 的目的。 而是拥有一个 ViewModel 实例并使用 OnPropertyChanged() 将错误传播到 View。

    当然有很多方法可以做到这一点,但我通常会在我的 View 中保留对 ViewModel 的引用,然后在 ViewModel 中保留对 Model 的引用。通过这种方式,Model 与 View/ViewModel 完全解耦,同样 ViewModel 与 View 解耦。

    【讨论】:

    • @Tele von Plan。如果你在 View 中持有 ViewModel 的引用,那么它是如何解耦的?它只适用于 Model/Viewmodel,因为您需要从 Viewmodel 调用模型函数。但是在 Viewmodel/View 的情况下,这些应该完全解耦。这可以通过将视图模型属性绑定到视图来实现,但不包括视图中任何视图模型的引用。
    • 嗯.. 我想更直接(和标准)的方法是将视图的 DataContext 分配给视图模型。这满足“无代码隐藏”。但这仍然涉及持有对视图模型的引用,所以它或多或少是一回事..
    • 我的解耦的意思是viewmodel不知道view的存在,model也不知道view或者viewmodel。
    • @Tele von Plan。我不采用这种方法。相反,我在那里也使用绑定并使用定位器来解析视图模型,而不是构建视图模型。 IE。我这样做 ....
    • @Tele von Plan。是的,它在这个意义上是解耦的。但我相信解决视图模型比构建它更好。除了查看这个link 来了解 MVVM 中的 8 种实例化方式。
    【解决方案2】:

    您不应该一次又一次地创建 MainWindowViewModel。它应该创建一次并设置为主窗口的数据上下文。

    问题在于您用于显示对话框的方法。这让事情变得复杂了。

    显示对话框的最佳解决方案是使用 mvvmlight 工具包的 messenger。检查this 以获取有关其用法的一些提示。

    这是您可以使用 mvvmlight 工具包的信使来显示对话框的方式:

    查看:

    Messenger.Default.Register<DialogMessage>(
             view,
             msg =>
             {
                 var result = MessageBox.Show(
                     msg.Content,
                     msg.Caption,
                     msg.Button,
                     msg.Icon);
             }
    );
    

    视图模型:

    private void ShowMessageBox(string msgStr, string capStr, MessageBoxButton btn, MessageBoxImage img)
    {
            var message = new DialogMessage(msgStr, null)
            {
                Button = btn,
                Caption = capStr,
                Icon = img
            };
    
            Messenger.Default.Send(message);
    }
    

    只需从任何视图模型中调用上述方法(ShowMessageBox)即可显示一个对话框。

    【讨论】:

    • 嗨哈桑,感谢您的回答。我不熟悉 Messenger 工具包。 “Messenger.Default.Register ...”应该放在 MainView.xaml 的代码隐藏中,但我看到 Messenger 在当前上下文中不存在。我需要补充什么?我猜 DialogMessage 只是我需要创建的一个类,它将 messageString 作为构造函数中的参数?我不确定为什么需要 null 作为第二个参数。或者可以在程序集引用中找到 DialogMessage?
    • @Kurmanc。从here 下载工具包。它为您提供了两个 dll。您需要在项目中添加对这些 dll 的引用 - GalaSoft.MvvmLight.WPF4 & GalaSoft.MvvmLight.Extras.WPF4。然后添加这个命名空间“使用 GalaSoft.MvvmLight.Messaging;”。希望一切都会顺利进行。此link 包含有关该工具包的信息并提供安装说明。
    • 谢谢哈桑,我去看看。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-01
    • 1970-01-01
    • 1970-01-01
    • 2014-06-17
    • 1970-01-01
    相关资源
    最近更新 更多