wpf 如何在MVVM中使用DialogService打开窗口?

oxf4rvwz  于 2023-03-04  发布在  其他
关注(0)|答案(1)|浏览(209)

我有一个对话服务

using RControl.Client.Abstractions;
using System;
using System.Windows;

namespace RControl.Client.Services;

public class DialogService : IDialogService
{
    public void ShowDialog<TViewModel>(TViewModel viewModel)
    {
        var window = new Window
        {
            Content = Activator.CreateInstance(ViewLocator.GetViewType(typeof(TViewModel))),
            DataContext = viewModel,
        };

        window.ShowDialog();
    }
}

另见视图定位器

using System;
using System.Linq;
using System.Reflection;

namespace RControl.Client;

public static class ViewLocator
{
    private const string ViewSuffix = "View";
    private const string ViewModelSuffix = "ViewModel";

    public static Type GetViewType(Type viewModelType)
    {
        var viewName = viewModelType.Name.Replace(ViewModelSuffix, string.Empty) + ViewSuffix;
        var viewType = Assembly.GetExecutingAssembly().GetTypes().FirstOrDefault(t => t.Name == viewName);

        return viewType ?? throw new ArgumentException($"View not found for {viewModelType.Name}.");
    }
}

但是当以这种方式使用该服务时

[RelayCommand]
private void About()
{
    var viewModel = new AboutViewModel();
    _dialogService.ShowDialog(viewModel);
}

抛出异常:系统操作无效异常:"Window对象必须是树的根。不能将Window对象添加为Visual的子对象。"
如何实现与相同的行为:

var window = new AboutView();
window.ShowDialog();
7qhs6swi

7qhs6swi1#

你应该把你要在窗口中显示的视图做成一个用户控件,而不是做所有getviewtype的事情,定义数据模板,通过数据类型把每个视图和一个视图模型联系起来。
如果您想自动化它,可以在代码生成器中使用元数据来构建它。
但您的窗口可能类似于:

<Window x:Class="LoginNavigation.LoginNavigationWindow"
    ...
    Title="{Binding Title}" Height="450" Width="800"
    Content="{Binding}"
    />

这个窗口可以用于任何你需要的窗口,它只是一个 shell ,包含你需要显示的任何东西。
关联用户控件:

<DataTemplate DataType="{x:Type local:MainViewModel}">
        <local:MainUC/>
    </DataTemplate>
    <DataTemplate DataType="{x:Type local:LoginViewModel}">
        <local:LoginUC/>
    </DataTemplate>

这些数据模板放在app.xaml中合并的资源字典中。
然后,您可以新建该窗口的示例,将datacontext设置为MainViewModel示例,窗口的内容将模板化到MainUC示例中。
您可以显示这样一个窗口对话框。
显然,保留对视图模型的引用以获取任何用户输入。

相关问题