使用WPF和MVVM打开新对话框

使用WPF和MVVM打开新对话框,wpf,mvvm,dialog,mvvm-light,showdialog,Wpf,Mvvm,Dialog,Mvvm Light,Showdialog,我目前正在使用MVVM(Light)构建一个带有WPF的应用程序。但是,在某些情况下,当用户单击按钮时,我必须打开一个新对话框(也是WPF)。然而,这是一场艰苦的战斗 我是这样做的: private void _ShowItemDialog(Item item) { var itemVM = new ItemViewModel(); itemVM.CurrentItem = item ?? new Item(); itemVM.Lo

我目前正在使用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的两个不同实例

在窗口标签内。为了在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中,这在窗口标记内声明如下:

my:DialogCloser.DialogResult="{Binding DialogResult}"
当对话框关闭时,关闭事件将DialogResult设置为true或false

这在第一次打开屏幕时效果很好,但关闭对话框后无法再次打开对话框

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

谢谢

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

通过这些更改,我发现不可能从ViewModelLocator使用ViewModel,因为它是一个“单例”,而不是每个新窗口的新实例。因此,DialogResult保留最后一个值,如果我试图将其值更改回null(就像ViewModel初始化时一样),则会引发异常。你知道为什么会这样吗?使用ViewModelLocator中的ViewModel对我来说是非常好的,因为它将在整个系统中保持相同的策略


谢谢大家!

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

这种实现方式的作用是,您可以轻松地修改静态交互类中的方法,以使用UnitTests

    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模式实现对话框的好方法。

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

这种实现方式的作用是,您可以轻松地修改静态交互类中的方法,以使用UnitTests

    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模式实现对话框的好方法。

我刚才已经这样做了,我使用了一个对话框服务,并在我的viewmodel中调用了这个服务

编辑:顺便说一句,这就是您在viewmodel中要做的全部工作

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

我不久前就做过这件事,我使用了一个对话框服务,并在我的viewmodel中调用了这个服务

编辑:顺便说一句,这就是您在viewmodel中要做的全部工作

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

不,我有静态方法的单元测试(我实际上没有在该方法中创建wpf窗口的实例,我有另一个类为我做这件事-AskUser.XXX)。请看一下我文章中添加的编辑部分。谢谢。不,我有静态方法的单元测试(我实际上没有在那个方法中创建wpf窗口的实例,我有另外一个类为我做这个-AskUser.XXX)。请看一下我文章中添加的编辑部分。谢谢。请看一下我在帖子中添加的编辑部分。谢谢。请看一下我在帖子中添加的编辑部分。谢谢你。我不确定你说的对不对。要为视图创建新的ViewModel实例,每次生成视图时,您都可以在“视图代码隐藏”中创建ViewModel的实例,并将Views DataContext设置为新生成的ViewModel。@Andre我不想为每个视图创建新的ViewModel。这正是奥波塞特。我想使用ViewModel singleton,但是我不明白为什么对新打开的窗口使用相同的实例不起作用。此外,为什么我不能“擦除”对话框结果?我不确定我是否理解正确。要为视图创建新的ViewModel实例,每次生成视图时,您都可以在“视图代码隐藏”中创建ViewModel的实例,并将Views DataContext设置为新生成的ViewModel。@Andre我不想为每个视图创建新的ViewModel。这正是奥波塞特。我想使用ViewModel singleton,但是我不明白为什么对新打开的窗口使用相同的实例不起作用。此外,为什么我不能“擦除”对话框结果?