Search code examples
c#wpfxamlmvvmprism

WPF, MVVM and PRISM - No Parameterless Constructor defined for this object


Answer OK so adding the suggested code given by E-Bat didn't have any affect until I started a new project and copied all the code across verbatim. I can only assume there must be some background code within the ViewModelLocator on http://prismlibrary.com/ which did not update to take the parameterless constructor into account. Hope this helps anyone else with the same issue

Original Question I have set up a MVVM project using prism. I have a MainWindow.xaml and 5 Views; ButtonsView, HeaderView, ProcessInputView, ProcessLogView and ProcessSelectionView which I am using, each View has an associated 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>

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));
    }
}

When I try to view the MainWindow in design mode I get the following Error Screenshot of MainWindow In design Mode

No Parameterless constructor found for this object - This Highlights the HeaderView and the ButtonsView

Both the HeaderViewModel and ButtonsViewModel take IEventAggregator as a parameter within their constructor where as the rest of the ViewModels do not. I am assuming this is where the errors are coming from.

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;
    }
}

So how can I get round this error if I need to subscribe to these events and hence need the IEventAggregator passed into my ViewModels?

Do I need to register this within the Bootstrap via an override of the ConfigureContainer method? If so I'm not entirely sure how to do this.

Bootstrap

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

    protected override void InitializeShell()
    {
        Application.Current.MainWindow.Show();
    }
}

The application builds successfully and runs successfully but it is just when trying to view the MainWindow in the designer that I get this message.

Any help would be greatly appreciated. EDIT All my view constructors just have the initalizeComponent methods and take no parameters


Solution

  • Your view is trying to execute logic that only make sense at runtime, so you need to make sure that you are not in design mode:

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

    EDIT:

    For support of designtime view model have a look here

    Basically you need to provide a parameterless constructor for you ViewModel to support design mode.