使用 WPF Prism / Mahapps HamburgerMenu 控件时调用参数化视图模型构造函数

Calling parameterised viewmodel constructor when using WPF Prism / Mahapps HamburgerMenu control

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

"No matching constructor found on type 'MyCompany.Wpf.Modules.Admin.Views.AdminDataGrid'. You can use the Arguments or FactoryMethod directives to construct this type.' Line number '236' and line position '34'." "No default constructor found for type 'MyCompany.Wpf.Modules.Admin.Views.AdminDataGrid'. You can use the Arguments or FactoryMethod directives to construct this type."

如果我在 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 部分 class AdminDataGrid:UserControl、IAdminDataGrid { // 我不得不添加它以获取 build/run 的代码。 publicAdminDataGrid() { 初始化组件(); }

    // 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 和继承自它们的 classes 创建接口,模块管理器代码是:

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

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

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

AdminMainViewModel 构造函数:

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

如何让 HamburgerMenu 控件在呈现 views:AdminDataGrid 项时使用参数化构造函数?谢谢。

How may I get the HamburgerMenu control to use the parameterised constructor when is renders the views:AdminDataGrid item?

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

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

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

此标记尝试使用默认构造函数创建 AdminDataGrid 的实例:

<views:AdminDataGrid />

当视图没有定义构造函数时,这显然不起作用。这意味着你不能在 XAML.

中像这样设置 HamburgerMenuIconItemTag 属性

如果您在代码隐藏中以编程方式设置它,您可以获取对注册表的引用并从那里解析视图模型,或者自己构建视图模型:

adminItem.Tag = new AdminMainView(new AdminMainViewModel());

XAML:

<Controls:HamburgerMenu.ItemsSource>
    <Controls:HamburgerMenuItemCollection>
        <Controls:HamburgerMenuIconItem x:Name="adminItem" Icon="{iconPacks:FontAwesome Kind=TableSolid}" Label="Data Grid" />
    </Controls:HamburgerMenuItemCollection>
</Controls:HamburgerMenu.ItemsSource>

无论哪种方式,XAML 处理器都不会为您解决依赖关系。