使用 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 创建视图模型两次(。 因此,我已将 AutoWireViewModel 值设置为 False,现在正在每个视图的代码隐藏中创建视图模型。我能够将创建视图模型时所需的依赖项注入视图构造函数 - 这也工作正常。 我遇到的问题是当我尝试使用Mahapps汉堡菜单控件时。这包含每个子视图的菜单项。 据我所知,每个子视图都需要一个无参数构造函数,但我需要一个参数化视图构造函数(注入创建/调用视图模型构造函数所需的依赖项(。我收到的异常/内部异常是:

"在类型'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 { 我不得不添加它才能构建/运行代码。 public AdminDataGrid(( { 初始化组件((; }

// 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上的属性(想法是为views:AdminDataGrid菜单项设置DataContext此属性 - 但不确定如何或这是否有效(。

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

AdminMainViewModel 构造函数:

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

如何让汉堡菜单控件在呈现视图:管理数据网格项时使用参数化构造函数? 谢谢。

此标记尝试使用默认构造函数创建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 处理器都不会为你解析依赖项。

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

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

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

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

相关内容

最新更新