【问题标题】:Opening a new dialog using WPF with MVVM使用带有 MVVM 的 WPF 打开一个新对话框
【发布时间】:2026-01-30 12:55:01
【问题描述】:

我目前正在使用 MVVM (Light) 来构建带有 WPF 的应用程序。但是,在某些情况下,当用户单击按钮时,我必须打开一个新对话框(也是 WPF)。然而,这是一场艰苦的战斗。

这是我的做法:

    private void _ShowItemDialog(Item item)
    {
        var itemVM = new ItemViewModel();
        itemVM.CurrentItem = item ?? new Item();
        itemVM.Load();

        var itemView = new View.ItemView() { DataContext = itemVM };
        if (itemView.ShowDialog() == true)
        {
            if (item == null)
            {
                itemList.Add(itemVM.CurrentItem);
            }
        }

        itemVM.Cleanup();
    }

并且 itemView XAML 没有绑定到 DataContext,否则会创建两个不同的 ViewModel 实例。

在 Window 标签内。为了在 ShowDialog 得到结果,我使用 DialogCloser 代码:

    public static class DialogCloser
    {
        public static readonly DependencyProperty DialogResultProperty =
            DependencyProperty.RegisterAttached(
                "DialogResult",
                typeof(bool?),
                typeof(DialogCloser),
                new PropertyMetadata(DialogResultChanged));

        private static void DialogResultChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var window = d as Window;
            if (window != null)
                window.DialogResult = e.NewValue as bool?;
        }

        public static void SetDialogResult(Window target, bool? value)
        {
            target.SetValue(DialogResultProperty, value);
        }
    }

在 ItemView 中,在 Window 标签内声明如下:

my:DialogCloser.DialogResult="{Binding DialogResult}"

并且当对话框关闭时,关闭事件将 DialogResult 设置为 true 或 false。

这在第一次打开屏幕时完美运行,但关闭后无法再次打开对话框。

我想知道您是否有更好的打开对话框的想法,以及为什么此代码不起作用。

谢谢!

编辑: 我已经修复了代码。我需要做的是创建一个新的 ViewModel 并将其附加到 DataContext 每次打开对话框时。此外,我必须从 XAML 中删除 DataContext 绑定。请检查上面的代码更改。

通过这些更改,我发现无法使用 ViewModelLocator 中的 ViewModel,因为它是“单例”,而不是每个新窗口中的新实例。因此,DialogResult 保存了最后一个值,如果我尝试将其值更改回 null(就像初始化 ViewModel 时一样),则会引发异常。你对为什么会发生这种情况有任何线索吗?使用 ViewModelLocator 中的 ViewModel 对我来说非常好,因为它会在整个系统中保持相同的策略。

谢谢!

【问题讨论】:

  • 我不确定我是否正确。要为您的 View 创建一个新的 ViewModel 实例,每次生成您的 View 时,您都可以在后面的 Views 代码中创建您的 ViewModel 的实例,并将 Views DataContext 设置为新生成的 ViewModel。
  • @Andre 我不想为每个视图创建一个新的视图模型。恰恰相反。我想使用 ViewModel 单例,但是我不明白为什么对打开的新窗口使用相同的实例不起作用。此外,为什么我不能“擦除” DialogResult?

标签: wpf mvvm dialog mvvm-light showdialog


【解决方案1】:

我通过实现静态 XxxxInteraction 类来做到这一点,这些类具有调用方法,例如 NewUser();该方法打开对话框并做一些工作。在我的 ViewModel 中,我通过命令调用 XxxxInteraction 类。

这种实现方式的努力在于,您可以轻松地修改静态交互类中的方法以使用 UnitTest。

    public static class UserInteractions
    {
        public static User NewUser()
        {
            var userDialog = new NewUserDialog();
            If(userDialog.ShowDialog() != true) return null;

            var user = new User();
            user.Name = userDialog.Name;
            user.Age = userDialog.Age;
            return user;
        }
    }

    public class MyViewModel
    {
        ...

        public void NewUserCommandExecute()
        {
            var newUser = UserInteractions.NewUser();
            if(newUser == null) return;

            //Do some with new created user
        }
    }

NewUserDialog 是一个普通的窗口,也绑定到一个 ViewModel。

我认为这是为 mvvm 模式实现对话框的好方法。

【讨论】:

  • 不,我对该静态方法进行了单元测试(实际上我没有在该方法中创建 wpf 窗口的实例,我有另一个类可以为我做这件事 - AskUser.XXX)。
  • 请看一下我帖子中添加的编辑部分。谢谢。
【解决方案2】:

我刚才做过这个,我使用对话服务并在我的视图模型中调用此服务。 take a look.

编辑:顺便说一句,这就是你在视图模型中要做的所有事情

var result = this.uiDialogService.ShowDialog("Dialogwindow title goes here", dialogwindowVM);

【讨论】:

  • 请看一下我帖子中添加的编辑部分。谢谢。
最近更新 更多