【问题标题】:Open dialog on already opened dialog MVVM在已打开的对话框 MVVM 上打开对话框
【发布时间】:2019-03-09 09:22:55
【问题描述】:

我观看了一个很棒的video,关于创建一个 DialogService 来负责在 MVVM 中打开对话框。由于 DialogService 构造函数以所有者(Window 类型)为参数,因此在 MainWindow 中创建 dialogService 很容易。只需在 App.xaml.cs 中分别为 MainWindow 创建一个 View 和一个 ViewModel 并连接所有东西。但问题是如何在从 MainWindow 打开的对话框中创建一个 dialogService(以从该对话框打开更多对话框),因为我无法获取从 MainWindowViewModel 打开的对话框的 View 实例。这是显示该对话框的方法。

private void ShowAdministrationDialog()
{
        AdministrationDialogViewModel viewModel = new AdministrationDialogViewModel(this.context);
        dialogService.ShowDialog(viewModel);
}

【问题讨论】:

    标签: c# mvvm dialog


    【解决方案1】:

    视频中的代码不支持您的用例。对话框服务似乎是一个单例,只能打开主窗口为所有者的对话框。在许多情况下这可能没问题,但对于像你这样的其他人来说,它根本行不通。

    我创建了一个名为 MvvmDialogs 的 NuGet 包,它能够在所有可能的情况下打开对话框。您可以在 GitHub 上浏览代码。我通过引入一个附加属性解决了这个问题,该属性充当视图和视图模型之间的桥梁。因此,我总是能够从视图模型跳转到它的视图,并从视图向上遍历逻辑 UI 树,直到到达拥有的窗口。

    这只是问题的一种解决方案,如果您想构建自己的对话服务,我相信您可以找到另一种解决方案。如果你不这样做,总会有 MvvmDialogs :D

    【讨论】:

    • 有没有办法在显示对话框时降低对话框所有者窗口的不透明度,然后在关闭时将其切换回正常状态?
    • 您的意思是在 MvvmDialogs 中还是在您自己实现的对话服务中?目前在 MvvmDialogs 中不支持它,但可以考虑一种解决方案,其中对话服务公开描述打开和关闭对话框的事件,您将能够挂钩这些事件以更新窗口不透明度。如果这对您有用,请创建一个问题,我们可以从那里着手。
    • 感谢您的包裹!我发布了一个问题。另外,如果我的项目用于商业用途,这个包可以免费使用吗?
    • 绝对。该代码在 Apache License 2.0 下获得许可,并将授予您在商业应用程序中使用的权限。但请在创建对包的依赖项之前阅读 Apache License 2.0。
    【解决方案2】:

    找到解决此问题的方法,但我不确定它是否会破坏 MVVM,因此 FantasticFiasco 的解决方案可能更好。在 DialogService 类中,将 ShowDialog 方法分离为 2 个方法 - PrepareDialog 和 ShowDialog

    准备对话:

    public void PrepareDialog<TViewModel>(TViewModel viewModel) where TViewModel : IDialogRequestClose
        {
            // Finds a ViewType from Mappings
            Type viewType = Mappings[typeof(TViewModel)];
    
            // Creates a View instance
            IDialog dialog = (IDialog)Activator.CreateInstance(viewType);
    
            // Adds an event on dialog close request
            EventHandler<DialogCloseRequestedEventArgs> handler = null;
            handler = (sender, e) =>
            {
                // Dispatch handler
                viewModel.CloseRequested -= handler;
    
                // Reset owner's opacity
                dialog.Owner.Opacity = 1;
    
                // Returns a result if exists
                if (e.DialogResult.HasValue)
                {
                    dialog.DialogResult = e.DialogResult;
                }
                else
                {
                    dialog.Close();
                }
            };
    
            dialog.DataContext = viewModel;
            dialog.Owner = owner;
            dialog.Owner.Opacity = 0.5;
    
            // Adds handler for close request
            viewModel.CloseRequested += handler;
    
            // Initializes a dialog service in opening dialog's ViewModel if supports it
            IViewModelDialogService viewModelDialogService = viewModel as IViewModelDialogService;
            if (viewModelDialogService != null)
            {
                viewModelDialogService.DialogService = new DialogService((Window)dialog);
            }
    
            this.newWindow = (Window)dialog;
        }
    

    显示对话框:

    public bool? ShowDialog()
        {
            if (this.newWindow == null)
            {
                throw new ArgumentNullException();
            }
    
            bool? result = this.newWindow.ShowDialog();
    
            this.newWindow = null;
    
            return result;
        }
    

    当然你需要在对话服务类中添加私有字段newWindow(类型Window)。现在这允许您在调用 PrepareDialog 时在 dialogService 中获取视图实例,并且在调用 PrepareDialog 之后您可以将更改应用到 ViewModel 的对话框服务,然后在最后调用 ShowDialog

    【讨论】:

    • 这是最好的解决方案!您可能应该以此为基础,而不是依赖于 MvvmDialogs,因为您可以完全控制自己编写的代码。祝你好运!
    猜你喜欢
    • 2010-12-20
    • 2015-12-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-23
    相关资源
    最近更新 更多