首页 > 解决方案 > 使用 WPF Prism / Mahapps HamburgerMenu 控件时调用参数化视图模型构造函数

问题描述

为试图获取尽可能多的信息而发表的长篇文章道歉。我正在使用 WPF (.NET Framework 4.8)、Prism 7、Prism.Unity 和 MahApps。几乎我所有的视图模型都需要参数化构造函数(注入依赖项)。我正在使用内置的 Prism ViewModelLocator.AutoWireViewModel 来连接视图模型(即 prism:ViewModelLocator.AutoWireViewModel="True")。一切正常,但这意味着创建了两个视图模型实例,一次是使用 AutoWireViewModel,另一次是在幕后调用参数化构造函数(请参阅 Brian Lagunas 的评论避免棱镜 AutoWireViewModel 创建 ViewModel 两次)。因此,我将 AutoWireViewModel 值设置为 False,现在在每个视图后面的代码中创建视图模型。我能够在创建视图模型时将所需的依赖项注入到视图构造函数中——这也可以正常工作。我遇到的问题是当我尝试使用 Mahapps HamburgerMenu 控件时。这包含每个子视图的菜单项。据我所知,每个子视图都需要一个无参数构造函数,但我需要一个参数化视图构造函数(注入创建/调用视图模型构造函数所需的依赖项)。我收到的异常/内部异常是:

“在 'MyCompany.Wpf.Modules.Admin.Views.AdminDataGrid' 类型上找不到匹配的构造函数。您可以使用 Arguments 或 FactoryMethod 指令来构造此类型。” 行号'236'和行位置'34'。” “找不到类型‘MyCompany.Wpf.Modules.Admin.Views.AdminDataGrid’的默认构造函数。您可以使用 Arguments 或 FactoryMethod 指令来构造此类型。”

如果我在 AdminDataGrid 视图中添加无参数构造函数,则不会出现错误,但我无法创建视图模型并传递依赖项。

我的代码如下:

包含 HamburgerMenu 的 AdminMainView 代码(问题子视图名为 AdminDataGrid):

<Controls:HamburgerMenu x:Name="HamburgerMenuControl"
                                HamburgerWidth="48"
                                IsPaneOpen="True"
                                CanResizeOpenPane="True"
                                ItemInvoked="HamburgerMenuControl_OnItemInvoked"
                                ItemTemplate="{StaticResource MenuItemTemplate}"
                                OptionsItemTemplate="{StaticResource MenuItemTemplate}"
                                SelectedIndex="0"
                                Style="{StaticResource MahApps.Styles.HamburgerMenu.Ripple}"
                                VerticalScrollBarOnLeftSide="False">
    <!--  Items  -->
    <Controls:HamburgerMenu.ItemsSource>
        <Controls:HamburgerMenuItemCollection>
            <Controls:HamburgerMenuIconItem Icon="{iconPacks:FontAwesome Kind=TableSolid}" Label="Data Grid">
                <Controls:HamburgerMenuIconItem.Tag>
                    <views:AdminDataGrid />
                </Controls:HamburgerMenuIconItem.Tag>
            </Controls:HamburgerMenuIconItem>
        </Controls:HamburgerMenuItemCollection>
    </Controls:HamburgerMenu.ItemsSource>

AdminDataGrid 视图的代码。第二个构造函数是我想调用的: public partial class AdminDataGrid : UserControl, IAdminDataGrid { // 我必须添加它来获取构建/运行的代码。公共 AdminDataGrid() { InitializeComponent(); }

    // This is the constructor I would like to call
    public AdminDataGrid(ICustomerService service)
    {
        InitializeComponent();

        this.DataContext = new AdminDataGridViewModel(service);
    }
}

AdminDataGridViewModel:

public class AdminDataGridViewModel : BindableBase, IAdminDataGridViewModel
{
    private ObservableCollection<Customer> _customers;
    public ObservableCollection<Customer> Customers
    {
        get => this._customers;
        set => SetProperty(ref _customers, value);
    }

    public AdminDataGridViewModel(ICustomerService service)
    {
        Customers = new ObservableCollection<Customer>();
        Customers.AddRange(service.GetAllCustomers().OrderBy(c => c.LastName));
    }
}

我已经尝试为 AdminDataGrid/AdminDataGridViewModel 创建接口,并且类从它们继承,模块管理器代码是:

public void RegisterTypes(IContainerRegistry containerRegistry)
{
    containerRegistry.Register<IAdminDataGrid, AdminDataGrid>();
    containerRegistry.Register<IAdminDataGridViewModel, AdminDataGridViewModel>();
}

后面的 AdminMainView 代码。注意:我注入 IAdminDataGridViewModel 对象并将其作为 AdminMainViewModel 上的属性公开(想法是将 DataContext 设置为视图的此属性:AdminDataGrid 菜单项 - 但不确定如何或是否可行)。

public AdminMainView(IAdminDataGridViewModel adminDataGridViewModel)
{
    this.InitializeComponent();
    this.DataContext = new AdminMainViewModel(adminDataGridViewModel);
}

AdminMainViewModel 构造函数:

public AdminMainViewModel(IAdminDataGridViewModel adminDataGridViewModel)
{
    this.AdminDataGridViewModel = adminDataGridViewModel;
}

当呈现视图时,如何让 HamburgerMenu 控件使用参数化构造函数:AdminDataGrid 项?谢谢。

标签: wpfmvvmconstructorprismmahapps.metro

解决方案


当呈现视图时,如何让 HamburgerMenu 控件使用参数化构造函数:AdminDataGrid 项?

你不会的。控件应该具有无参数的构造函数,这就是ViewModelLocator为了规避而发明的。

我只是使用它来创建视图模型(所有必需的依赖项作为构造函数参数),而不是手动创建和分配数据上下文。

话虽如此,也可以选择先查看模型,而且大多数情况下最好先查看模型。


推荐阅读