Dependency Injection using Template 10

2019-02-20 18:15发布

I am trying to migrate some code from an old Windows 8.1 app that I had developed using Prism/Unity to a new UWP app using Template 10 and Unity. I have seen in the documentation for Template 10 here that you can override the ResolveForPage method.

In my old Windows 8.1 app, there is a Resolve method in Prism that I would override like this:

protected override object Resolve(Type type)
{
    return Container.Resolve(type);
}

The signature for the Template 10 method is

public override INavigable ResolveForPage(Page page, NavigationService navigationService)

so I am not exactly sure how to convert this. I have registered my repository in OnInitializeAsync in my App.xaml.cs, like so:

Container.RegisterType<IPayeesRepository, PayeesRepository>(new ContainerControlledLifetimeManager());

Where Container is a UnityContainer instance. My problem is that when I try to inject the dependency on another page, I get a NullReferenceException because _payeesRepository is null. It seems to me like the constructor with the dependency injection is not being called, and if I remove the default constructor then I get an error. Has anyone gotten Unity to work with Template 10 that may have any suggestions what I may be missing?

I also tried using the Dependency attribute like so:

[Dependency]
private IPayeesRepository _payeesRepository { get; set; }

But that doesn't work either. It seems like the IPayeesRepository is just not being instantiated, but I'm not exactly sure. In my Windows 8.1 app, it is never explicitly instantiated, so I have a feeling it has something to do with not overriding the Resolve method.

1条回答
手持菜刀,她持情操
2楼-- · 2019-02-20 18:38

I made it work (but In my case I'm having another anoying issue I'll mention later and probably in a SO quiestion too).

On the one hand, the Ask Too Much's answer to this question guided me to solve this problem with ViewModel's DI.

In App.xaml.cs:

public override async Task OnStartAsync(StartKind startKind, IActivatedEventArgs args)
{
    // long-running startup tasks go here
    AppController.Initialize();
    await Task.CompletedTask;
}

AppController is the place where I configure the app, including the container.

next, in App.xaml.cs:

public override INavigable ResolveForPage(Page page, NavigationService navigationService)
{
    if (page is MainPage)
    {
        return SimpleIoc.Default.GetInstance<MainPageViewModel>();
        //(AppController.UnityContainer as UnityContainer).Resolve<INavigable>();
    }
    else
        return base.ResolveForPage(page, navigationService);
}

But you also have to:

Remove <Page.DataContext> from the Page XAML. Remove constructors from page.xaml.cs, my MainPage.xaml.cs is like this

public sealed partial class MainPage : Page
{
    MainPageViewModel _viewModel;

    public MainPageViewModel ViewModel
    {
        get { return _viewModel ?? (_viewModel = (MainPageViewModel)DataContext); }
    }    
}

Inject your dependencies on your VM:

public MainPageViewModel(IShapeService shapeService)
{     
   // this is just a POC            
}

And that's all, it should work for you.

I updated the wiki with this same information in a while... Also, just let you know that I made it to work with Unity and with MVVMLight.SimpleIoC with same result, a System.PlatformNotSupportedException due to what IShapeService really is is a WCF proxy that is in a PCL library that I'll have to refactor because I just realize that UWP doesn't support config files (lol!)

I hope it helps and save you time.

查看更多
登录 后发表回答