【问题标题】:Opening a choice of views depending on database read from the view model with MVVM根据使用 MVVM 从视图模型读取的数据库打开视图选择
【发布时间】:2021-02-07 11:17:41
【问题描述】:

在我的 WPF MVVM 项目中,我有一些表单和一个保存员工信息的数据库。有一个员工视图模型,这有一个 employeeId 传递给它,使用员工模型,员工的详细信息从数据库中读取。这也会读取员工是“用户”还是“管理员”。

然后视图模型将决定加载哪个视图。用户视图或管理员视图。这两个视图之间有很多相似之处,这就是为什么我对两者都使用相同的视图模型。

这就是为什么对于我的项目,我决定保持一致并让我的视图模型打开它们的视图。但是,在网上研究我只能看到建议说要实例化视图,然后在视图构造函数中创建视图模型。

我的方法对 MVVM 来说是错误的方式吗?我该如何以正确的方式处理这种情况?

MainWindowViewModel

    public void OpenSelectedEmployee(object employee)
    {
        if (employee == null)
            return;

        StaffListModel model = (StaffListModel)employee;

        EmployeeViewModel vm = new EmployeeViewModel(model.EmployeeId);
    }

EmployeeViewModel

    private EmployeeModel employee;
    private Window employeeWindow;
    
    // Employee View Model Constructor
    public EmployeeViewModel(int employeeId)
    {
        // Connect to DB and read data for employee class
        if (LoadEmployee(employeeId))
        {
            if (employee.UserType == "User")
                employeeWindow = new EmployeeUserDetailsView();
            else // if Admin
                employeeWindow = new EmployeeAdminDetailsView();
            
            employeeWindow.DataContext = this;
            employeeWindow.ShowDialog();
        }
        else
        {
            // Open error message
            MessageBox.Show("Error loading employee occurred");
        }
    }

我已经考虑将用户类型存储在主窗口视图模型中,以便决定打开哪个视图。但是,如果出于某种原因数据库无法读取员工 (LoadEmployee(employeeId)),则创建视图毫无意义,我希望显示错误消息框。

编辑: 这是EmployeeViewModel 中当前的LoadEmployee 方法。它在构造函数中使用,并通过绑定按钮刷新表单。

    public bool LoadEmployee(int employeeId)
    {
        if (!DbConnector.OpenDB())
            return false;

        try
        {
            employee = EmployeeModel.FindById(employeeId);
            Depots = DepotModel.FindAllShort();
            Departments = EmployeeModel.FindAllDepartments();
            TenureHistory = TenureHistoryModel.FindAllByEmployeeId(employeeId);
            IdCards = IdCardModel.FindAllByEmployeeId(employeeId);
            Qualifications = QualificationModel.FindAllByEmployeeId(employeeId);
            TheoryBookings = TheoryBookingModel.FindAllByEmployeeId(employeeId);
            MedicalRecords = MedicalRecordModel.FindAllByEmployeeId(employeeId);
            EyesightChecks = EyesightCheckModel.FindAllByEmployeeId(employeeId);
        }
        catch
        {
            DbConnector.CloseDB();
            return false;
        }

        DbConnector.CloseDB();
        return true;
    }
    public void Refresh(object parameter)
    {
        if (!LoadEmployee(employee.EmployeeId))
            MessageBox.Show("An error has occurred");

        NotifyPropertyChanged(string.Empty);
    }

【问题讨论】:

    标签: c# wpf mvvm


    【解决方案1】:

    从视图模型创建或引用视图或窗口违反并有效地破坏了 MVVM 设计模式。

    您应该将IWindowService 的实现注入您的MainWindowViewModel,该实现负责创建窗口:

    public class WindowService : IWindowService
    {
        public void ShowDialog(EmployeeViewModel viewModel, EmployeeModel model)
        {
            if (LoadEmployee(model.employeeId))
            {
                Window employeeWindow;
                if (model.UserType == "User")
                    employeeWindow = new EmployeeUserDetailsView();
                else // if Admin
                    employeeWindow = new EmployeeAdminDetailsView();
    
                employeeWindow.DataContext = viewModel;
                employeeWindow.ShowDialog();
            }
            else
            {
                // Open error message
                MessageBox.Show("Error loading employee occurred");
            }
        }
    }
    

    MainWindowViewModel:

    private readonly IWindowService _windowService;
    
    public MainWindowViewModel(IWindowService windowService)
    {
        _windowService = windowService;
    }
    
    public void OpenSelectedEmployee(object employee)
    {
        if (employee == null)
            return;
    
        StaffListModel model = (StaffListModel)employee;
    
        EmployeeViewModel vm = new EmployeeViewModel(model.EmployeeId);
    
        _windowService.ShowDialog(vm, model);
    }
    

    另一个例子见我的回答here

    【讨论】:

    • 谢谢。我已经对其进行了更改,因此我的视图模型构造函数采用了employeeId,并且用户类型是从视图模型中的公共方法中获取的。不过,我没有看到任何创建接口的理由,为什么不直接使用 WindowService 类?
    • @smally:因为它对System.Windows.Window类型有很强的依赖,不能在单元测试中被mock。
    • 因此,如果我要从 EmployeeViewModel 的视图中显示一个新窗口,我是否需要将 _windowService 传递给 EmployeeViewModel 的构造函数。或者它应该是一个新的,比如EmployeeViewModel vm = new EmployeeViewModel(new WindowService(), model.EmployeeId)
    • 是的,您应该将接口的实现传递给视图模型。
    • 所以对于我的项目的其余部分,当打开新窗口时,如果数据加载失败,我只想打开窗口或错误消息框。这样做会是一个好方法并且符合 MVVM 吗? pastebin.com/TarUpdac
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-12-16
    • 1970-01-01
    • 2012-08-06
    • 2020-09-30
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多