How do I use a Unity IoC container with Template10?
Asked Answered
P

2

9

I have an app based on Template10 and want to handle my dependency injection using IoC. I am leaning toward using Unity for this. My app is divided into three assemblies:

  1. UI (Universal app)
  2. UI Logic (Universal Library)
  3. Core Logic (Portable Library).

I have these questions:

  1. Should I use a single container for the whole app, or create one for each assembly?
  2. Where should I create the container(s) and register my services?
  3. How should different classes in the various assemblies access the container(s)? Singleton pattern?

I have read a lot about DI and IoC but I need to know how to apply all the theory in practice, specifically in Template10.

The code to register:

// where should I put this code?
var container = new UnityContainer();
container.RegisterType<ISettingsService, RoamingSettingsService);

And then the code to retrieve the instances:

var container = ???
var settings = container.Resolve<ISettingsService>();
Paederast answered 26/5, 2016 at 5:42 Comment(1)
Possible duplicate of Ioc/DI - Why do I have to reference all layers/assemblies in entry application?Grizel
E
3

I not familiar with Unity Container.

My example is using LightInject, you can apply similar concept using Unity. To enable DI on ViewModel you need to override ResolveForPage on App.xaml.cs on your project.

public class MainPageViewModel : ViewModelBase
{
    ISettingsService _setting;
    public MainPageViewModel(ISettingsService setting)
    {
       _setting = setting;
    }
 }


[Bindable]
sealed partial class App : Template10.Common.BootStrapper
{
    internal static ServiceContainer Container;

    public App()
    {
        InitializeComponent();
    }

    public override async Task OnInitializeAsync(IActivatedEventArgs args)
    {
        if(Container == null)
            Container = new ServiceContainer();

        Container.Register<INavigable, MainPageViewModel>(typeof(MainPage).FullName);
        Container.Register<ISettingsService, RoamingSettingsService>();

        // other initialization code here

        await Task.CompletedTask;
    }

    public override INavigable ResolveForPage(Page page, NavigationService navigationService)
    {
        return Container.GetInstance<INavigable>(page.GetType().FullName);
    }
}

Template10 will automaticaly set DataContext to MainPageViewModel, if you want to use {x:bind} on MainPage.xaml.cs :

public class MainPage : Page
{
    MainPageViewModel _viewModel;

    public MainPageViewModel ViewModel
    {
      get { return _viewModel??(_viewModel = (MainPageViewModel)this.DataContext); }
    }
}
Echino answered 12/6, 2016 at 11:10 Comment(2)
Thanks for the answer! This worked well for me! Is there a way to inject VM into Shell view?Etiquette
@NickGoloborodko I'm not quite understand about your question, maybe you should create new SO question about this?Echino
S
0

here is a small example how i use Unity and Template 10.

1. Create a ViewModel

I also created a DataService class to create a list of people. Take a look at the [Dependency] annotation.

public class UnityViewModel : ViewModelBase
{
    public string HelloMessage { get; }

    [Dependency]
    public IDataService DataService { get; set; }

    private IEnumerable<Person> people;
    public IEnumerable<Person> People
    {
        get { return people; }
        set { this.Set(ref people, value); }
    }

    public UnityViewModel()
    {
        HelloMessage = "Hello !";
    }

    public override async Task OnNavigatedToAsync(object parameter, NavigationMode mode,
        IDictionary<string, object> suspensionState)
    {
        await Task.CompletedTask;
        People = DataService.GetPeople();
    }
}

2. Create a Class to create and fill your UnityContainer

Add the UnityViewModel and the DataService to the unityContainer. Create a property to resolve the UnityViewModel.

public class UnitiyLocator
{
    private static readonly UnityContainer unityContainer;

    static UnitiyLocator()
    {
        unityContainer = new UnityContainer();
        unityContainer.RegisterType<UnityViewModel>();
        unityContainer.RegisterType<IDataService, RuntimeDataService>();
    }

    public UnityViewModel UnityViewModel => unityContainer.Resolve<UnityViewModel>();
}

3. Add the UnityLocator to your app.xaml

<common:BootStrapper x:Class="Template10UWP.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:common="using:Template10.Common"
                 xmlns:mvvmLightIoc="using:Template10UWP.Examples.MvvmLightIoc"
                 xmlns:unity="using:Template10UWP.Examples.Unity">


<Application.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <ResourceDictionary Source="Styles\Custom.xaml" />
            <ResourceDictionary>
                <unity:UnitiyLocator x:Key="UnityLocator"  />
            </ResourceDictionary>
        </ResourceDictionary.MergedDictionaries>

        <!--  custom resources go here  -->

    </ResourceDictionary>
</Application.Resources>

4. Create the page

Use the UnityLocator to set the UnityViewModel as DataContext and bind the properties to the controls

<Page
x:Class="Template10UWP.Examples.Unity.UnityMainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Template10UWP.Examples.Unity"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
DataContext="{Binding Source={StaticResource UnityLocator}, Path=UnityViewModel}"
mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
    <Grid.RowDefinitions>
        <RowDefinition Height="Auto" />
        <RowDefinition Height="*" />
    </Grid.RowDefinitions>
    <TextBlock Text="{Binding HelloMessage}" HorizontalAlignment="Center"
               VerticalAlignment="Center" />

    <ListBox Grid.Row="1" ItemsSource="{Binding People}" DisplayMemberPath="FullName">

    </ListBox>
</Grid>

The DataService will be injected automatically when the page resolves the UnityViewModel.

Now to your questions

  1. This depends on how the projects depend on each other. I am not sure what´s the best solution, but i think i would try to use one UnityContainer and place it in the core library.

  2. I hope my examples answered this question

  3. I hope my examples answered this question

Shorthanded answered 7/4, 2017 at 13:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.