WPF,MVVM和PRISM - 为此对象定义的无参数构造函数

ghe*_*eff 4 c# wpf xaml prism mvvm

回答 OK,所以添加E-Bat给出的建议代码没有任何影响,直到我开始一个新项目并逐字复制所有代码.我只能假设在http://prismlibrary.com/上的ViewModelLocator中必须有一些后台代码,它们没有更新以考虑无参数构造函数.希望这可以帮助其他人解决同样的问题

原始问题 我使用棱镜设置了一个MVVM项目.我有一个MainWindow.xaml和5个视图; 我正在使用的ButtonsView,HeaderView,ProcessInputView,ProcessLogView和ProcessSelectionView,每个View都有一个关联的ViewModel.

MainWindow.xaml

<Window x:Class="TransactionAutomationTool.Views.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:TransactionAutomationTool"
    xmlns:views="clr-namespace:TransactionAutomationTool.Views"
    xmlns:prism="http://prismlibrary.com/"
    prism:ViewModelLocator.AutoWireViewModel="True"
    mc:Ignorable="d"
    Title="MainWindow" Height="600" Width="800">
<Grid>
    <views:HeaderView x:Name="HeaderViewControl" Margin="20,21,0,0" />
    <views:ProcessSelectionView x:Name="ProcessSelectionViewControl" Margin="20,119,0,0" />
    <views:ProcessInputView x:Name="ProcessInputViewControl" Margin="20,280,0,0" />
    <views:ProcessLogView x:Name="ProcessLogView" Margin="298,105,0,0" />
    <views:ButtonsView x:Name="ButtonViewControl" Margin="0,513,0,0" />
</Grid>
Run Code Online (Sandbox Code Playgroud)

MainWindowViewModel

public class MainWindowViewModel: BindableBase
{

    public IEventAggregator _events;
    private UserPrincipal userPrincipal;
    public MainWindowViewModel(IEventAggregator events)
    {
        _events = events;
        userPrincipal = UserPrincipal.Current;
        _events.GetEvent<HeaderLoaded>().Subscribe(HeaderHasBeenLoaded);

    }

    private void HeaderHasBeenLoaded()
    {
        _events.GetEvent<UserNameUpdate>().Publish(string.Format("{0} {1}", userPrincipal.GivenName, userPrincipal.Surname));
    }
}
Run Code Online (Sandbox Code Playgroud)

当我尝试在设计模式下查看MainWindow时,我在设计模式下获得以下错误 的MainWindow屏幕截图

找不到此对象的无参数构造函数 - 这突出显示了HeaderView和ButtonsView

HeaderViewModel和ButtonsViewModel都将IEventAggregator作为其构造函数中的参数,而ViewModel的其余部分则不然.我假设这是错误的来源.

HeaderViewModel

public class HeaderViewModel: BindableBase
{
    private string userName;
    private string runTime;

    public string UserName
    {
        get { return userName; }
        set { SetProperty(ref userName, value); }
    }

    public string RunTime
    {
        get { return runTime; }
        set { SetProperty(ref runTime, value); }
    }

    public HeaderViewModel(IEventAggregator events)
    {
        events.GetEvent<RunTimeUpdate>().Subscribe(RunTimeUpdated);
        events.GetEvent<UserNameUpdate>().Subscribe(UserNameUpdated);
        events.GetEvent<HeaderLoaded>().Publish();
    }

    private void RunTimeUpdated(string newRunTime)
    {
        RunTime = newRunTime;
    }

    private void UserNameUpdated(string userName)
    {
        UserName = userName;
    }
}
Run Code Online (Sandbox Code Playgroud)

那么如果我需要订阅这些事件并因此需要将IEventAggregator传递给我的ViewModel,我怎么能解决这个错误呢?

我是否需要通过覆盖ConfigureContainer方法在Bootstrap中注册?如果是这样,我不完全确定如何做到这一点.

引导

class Bootstraper: UnityBootstrapper
{
    protected override DependencyObject CreateShell()
    {
        return Container.Resolve<MainWindow>();
    }

    protected override void InitializeShell()
    {
        Application.Current.MainWindow.Show();
    }
}
Run Code Online (Sandbox Code Playgroud)

应用程序构建成功并成功运行,但只是在尝试查看设计器中的MainWindow时,我收到此消息.

任何帮助将不胜感激.编辑我的所有视图构造函数都只有initalizeComponent方法,并且不带参数

Nei*_*eil 5

标记为已接受的答案解决了例外情况,但未回答有关原因的问题.此外,这种方法会使单元测试变得非常困难,因为您将datacontext设置为特定对象而不是传递依赖项.

您获得异常的原因是因为HeaderView没有被容器实例化(默认情况下它是UnityContainer).

您在设计时构建整个MainWindow而不是单个部分.在MainWindow中尝试以下操作

<Grid>
<Grid.RowDefinitions>
 <RowDefinitions />
 <RowDefinitions />
 <RowDefinitions />
 <RowDefinitions />
 <RowDefinitions />
</Grid.RowDefinitions>
<ContentControl Grid.Row="0" prism.RegionManager.RegionName="Row0Region" />
<ContentControl Grid.Row="1" prism.RegionManager.RegionName="Row1Region" />
<ContentControl Grid.Row="2" prism.RegionManager.RegionName="Row2Region" />
<ContentControl Grid.Row="3" prism.RegionManager.RegionName="Row3Region" />
<ContentControl Grid.Row="4" prism.RegionManager.RegionName="Row4Region" />
</Grid>
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用View Discovery或View Injection.对于View Discovery,您可以执行类似的操作

this.RegionManager.RegisterViewWithRegion("Row0Region", HeaderView()) 等等其他观点.

您可以在初始化模块方法或其他位置的区域中注册视图.关于你在哪里做到这一点.您可以覆盖引导程序的Run方法.基本运行方法完成后,您可以注册您的视图.

显示主窗口时,将发现所有区域RegionManager,并使用已注册到每个区域的视图填充区域.

regionmanager将使用容器实例化视图.当容器构造每个视图时,它们的视图模型将自动连接起来.此外,IEventAggregator还将提供给HeaderView视图模型.

本文基于棱镜4 - https://www.codeproject.com/Articles/165376/A-Prism-Application-Checklist,但它讨论了如何构建视图.


E-B*_*Bat 2

您的视图试图执行仅在运行时有意义的逻辑,因此您需要确保您不处于设计模式:

public HeaderView()
{
    if (!System.ComponentModel.DesignerProperties.GetIsInDesignMode(this))
    {
        var svc = ServiceLocator.Current;
        var eventAggregator = svc.GetInstance<IEventAggregator>();
        this.DataContext = new HeaderViewModel(eventAggregator);
     }
     InitializeComponent();
}
Run Code Online (Sandbox Code Playgroud)

编辑:

对于设计时视图模型的支持看看此处

基本上,您需要为 ViewModel 提供一个无参数构造函数来支持设计模式。