ajay_whiz
ajay_whiz

Reputation: 17951

Caliburn Micro get service instance

I am using Caliburn Micro for WinRT apps. I have registered a service in my App.xaml.cs see sample code below

public sealed partial class App
    {
        private WinRTContainer _container;

      public App()
        {
            InitializeComponent();
            Resuming += AppResuming;
        }

        protected override void Configure()
        {
            _container = new WinRTContainer();

            _container.RegisterWinRTServices();

            _container.Singleton<ISampleService, SampleService>();
            //some more viewmodels & services added
        }

protected override void PrepareViewFirst(Frame rootFrame)
        {
            _container.RegisterNavigationService(rootFrame);
        }

protected override object GetInstance(Type service, string key)
        {
            return _container.GetInstance(service, key);
        }

        protected override IEnumerable<object> GetAllInstances(Type service)
        {
            return _container.GetAllInstances(service);
        }

        protected override void BuildUp(object instance)
        {
            _container.BuildUp(instance);
        }
}

Now, I have a utility class in which I want to get the instance of this SampleService.

How can I get the instance?

Upvotes: 0

Views: 2181

Answers (3)

Anton Kedrov
Anton Kedrov

Reputation: 1767

In most cases you should avoid pulling things from the container directly. Instead, consider using dependency injection.

For example, if you want to use ISampleService in SomeUtility class, which is called from SomeViewModel, then first you will need to register all three types in the container.

public class AppBootstrapper : BootstrapperBase
{
    protected override void Configure()
    {
        ...

        _container.Singleton<ISampleService, SampleService>();
        _container.Singleton<SomeUtility>();
        _container.PerRequest<SomeViewModel>();
    }
}

Now, since SomeUtility depends on ISampleService, you should create SomeUtility constructor, which will accept ISampleService.

class SomeUtility
{
    private ISampleService _service;

    public SomeUtility(ISampleService service)
    {
        _service = service;
    }
}

And if SomeViewModel will be using SomeUtility, then appropriate constructor should be added to SomeViewModel as well.

class SomeViewModel : Caliburn.Micro.Screen
{
    private SomeUtility _utility;

    public SomeViewModel(SomeUtility utility)
    {
        _utility = utility;
    }
}

Finally, let's add SomeViewModel into ShellViewModel constructor.

class ShellViewModel : PropertyChangedBase, IShell
{
    private SomeViewModel _vm;

    public ShellViewModel(SomeViewModel vm)
    {
        _vm = vm;
    }
}

That's it! ShellViewModel will get SomeViewModel instance, SomeViewModel will get SomeUtility and SomeUtility will have your ISampleService. And all this will be resolved by Container, so you don't need to create manually new SomeUtility(); or pull from the container IoC.Get<ISampleService>();.

Also you might be wondering: What if SomeViewModel should be created on request, for example, when user click "Add" button? Well, I glad you asked. :) For that case you can use a factory method!

Just register it with the container.

public class AppBootstrapper : BootstrapperBase
{
    protected override void Configure()
    {
        ...

        _container.Handler<IScreen>((x) => x.GetInstance<SomeViewModel>());
    }
}

Now you can easily inject it into constructor and use it to create as many instances of SomeViewModel as needed.

class ShellViewModel : Conductor<IScreen>.Collection.AllActive, IShell
{
    private Func<SomeViewModel> _vmFactory;

    public ShellViewModel(Func<SomeViewModel> vmFactory)
    {
        _vmFactory = vmFactory;
    }

    public void Add()
    {
        var newVM = _vmFactory();
        ActivateItem(newVM);
    }
}

Upvotes: 1

Igor Kulman
Igor Kulman

Reputation: 16361

The answer from Guerudo works, but you should never use IoC.Get<> unless you absolutely have to. Using a service locator is considered an anti-pattern.

The right when do get an instance is to use constructor injection. Say you have a MainViewModel, the do this

public class MainViewModel
{
    private readonly ISampleService _sampleService;

    public MainViewModel(ISampleService sampleService)
    {
        _sampleService = sampleService   
    }

}

And use _sampleService anywhere in your ViewModel.

And there is no need for any MEF attributes with Caliburn.Micro.

Upvotes: 2

Guerudo
Guerudo

Reputation: 361

I'm supposing you are using MEF with Caliburn.Micro

So you can get an instance this way :

SampleService service = IoC.Get<ISampleService>();

Hope this will help you.

Upvotes: 2

Related Questions