2

I may be going about this all wrong, but I thought I was on the right path. I'm building a WPF app for the first time and am still getting used to some of the ways things are done.

My Thinking

  • My goal is to make my ViewModel class more testable.
  • The ViewModel depends on a service class and wouldn't be functional without it.
  • Therefore, it seems to make sense to me to inject the service into the ViewModel so that I can also start mocking it for testing purposes.

What I did

  • Made a XAML reference to my view model, which is called "UploaderViewModel":
 <Window.DataContext>
     <viewModels:UploaderViewModel>
         </viewModels:UploaderViewModel>
 </Window.DataContext>

NOTE: This works fine before I try to do the injection

  • Set up structure map in my app.xaml.cs file:
   void App_Startup(object sender, StartupEventArgs eventArgs)
    {
        ContainerBootstrapper.BootstrapStructureMap();
        ProcessStartupArguments(eventArgs);
    }

Which calls my bootstrapper class:

public static class ContainerBootstrapper
{
    public static void BootstrapStructureMap()
    {
        ObjectFactory.Initialize(
            x => x.For<IVEDocumentService>().Use<VEDocumentService>()
            );
    }
}
  • I then have my UploaderViewModel class take the IVEDocumentService as a Constructor parameter:

    public UploaderViewModel(IVEDocumentService documentService)
    {
        _documentService = documentService;
        //other unrelated code below this
     }
    

What's Going Wrong

I'm receiving an XAML error that says there's no default constructor found for the ViewModel, which makes sense, since I have no UploaderViewModel(), only UploaderViewModel(IVEDocumentService documentService).

Question

  • What's the best way to resolve this?
  • Should I create an UploaderViewModel() constructor and make StructureMap call UploaderViewModel with an instance of the service, or is there a better way?

Update 1 -- Attempting to Use a Resource Dictionary, StructureMap error.

Based on this SO Answer to a similar question, I tried:

  • Updating my App_Startup to add an instance of the UploaderViewModel to a resources dictionary:
void App_Startup(object sender, StartupEventArgs eventArgs)
{
  ContainerBootstrapper.BootstrapStructureMap();

var uploaderViewModel = new UploaderViewModel(new Container().GetInstance<IVEDocumentService>());
Current.Resources["UploaderViewModel"] = uploaderViewModel;

ProcessStartupArguments(eventArgs);

}
  • Added DataContext="{StaticResource UploaderViewModel}" to my <Window> declaration
  • Commented out my <viewModels:UploaderViewModel/> declaration

Upon doing this, StructureMap now throw an error:

"StructureMap Exception Code: 202No Default Instance defined for PluginFamily

Community
  • 1
  • 1
SeanKilleen
  • 8,809
  • 17
  • 80
  • 133
  • The 202 error indicates that StructureMap can't resolve the requested type or one of it's dependencies. If you look at the full error or the inner exception you should be able to see which type it is that StructureMap don't know how to construct. Does the `VEDocumentService` have any dependencies injected in the constructor? – PHeiberg Aug 05 '13 at 12:55
  • `VEDocumentService` actually doesn't have a constructor at all. It currently consists of only one public method. The inner exception on the error message is null. – SeanKilleen Aug 05 '13 at 14:06

1 Answers1

1

I figured it out. I think I wasn't configuring the static resource correctly. The solution, using StructureMap, was to do the following:

App.xaml.cs

   void App_Startup(object sender, StartupEventArgs eventArgs)
    {
        ContainerBootstrapper.BootstrapStructureMap();
        //Other logic
     }

ContainerBootstrapper Class

public static void BootstrapStructureMap()
{
    ObjectFactory.Initialize(x => x.For<IVEDocumentService>().Use<VEDocumentService>());
}

MainWindow.xaml.cs

I moved the resource creation into this class:

public MainWindow()
{
    var uploaderViewModel = new UploaderViewModel(ObjectFactory.GetInstance<IVEDocumentService>());
    this.Resources["UploaderViewModel"] = uploaderViewModel;
    InitializeComponent();
}

MainWindow.xaml

On the <Window> definition, I set DataContext="{StaticResource UploaderViewModel}".

Works like a charm. I believe it was a combination of not binding the resources at the proper scope (window).

SeanKilleen
  • 8,809
  • 17
  • 80
  • 133