c# - How to handle dependency injection in a WPF/MVVM application -
i starting new desktop application , want build using mvvm , wpf.
i intending use tdd.
the problem don´t know how should use ioc container inject dependencies on production code.
suppose have folowing class , interface:
public interface istorage { bool savefile(string content); } public class storage : istorage { public bool savefile(string content){ // saves file using streamwriter } }
and have class has istorage
dependency, suppose class viewmodel or business class...
public class someviewmodel { private istorage _storage; public someviewmodel(istorage storage){ _storage = storage; } }
with can write unit tests ensure working properly, using mocks , etc.
the problem when comes use in real application. know must have ioc container links default implementation istorage
interface, how may it?
for example, how if had following xaml:
<window ... xmlns definitions ... > <window.datacontext> <local:someviewmodel /> </window.datacontext> </window>
how can correctly 'tell' wpf inject dependencies in case?
also, suppose need instance of someviewmodel
cs
code, how should it?
i feel i´m lost in this, appreciate example or guidance of how best way handle it.
i familiar structuremap, i´m not expert. also, if there better/easier/out-of-the-box framework, please let me know.
thanks in advance.
i have been using ninject, , found it's pleasure work with. set in code, syntax straightforward , has documentation (and plenty of answers on so).
so goes this:
create view model, , take istorage interface constructor parameter:
class usercontrolviewmodel { public usercontrolviewmodel(istorage storage) { } }
create viewmodellocator property view model, loads view model ninject:
class viewmodellocator { public usercontrolviewmodel usercontrolviewmodel { { return iockernel.get<usercontrolviewmodel>();} // loading usercontrolviewmodel automatically load binding istorage } }
make viewmodellocator application wide resource in app.xaml:
<application ...> <application.resources> <local:viewmodellocator x:key="viewmodellocator"/> </application.resources> </application>
bind datacontext of usercontrol corresponding property in viewmodellocator.
<usercontrol ... datacontext="{binding usercontrolviewmodel, source={staticresource viewmodellocator}}"> <grid> </grid> </usercontrol>
create class inheriting ninjectmodule, set necessary bindings (istorage , viewmodel):
class iocconfiguration : ninjectmodule { public override void load() { bind<istorage>().to<storage>().insingletonscope(); // reuse same storage every time bind<usercontrolviewmodel>().toself().intransientscope(); // create new instance every time } }
initialize ioc kernel on application startup necessary ninject modules (the 1 above now):
public partial class app : application { protected override void onstartup(startupeventargs e) { iockernel.initialize(new iocconfiguration()); base.onstartup(e); } }
i have used static iockernel class hold application wide instance of ioc kernel, can access when needed:
public static class iockernel { private static standardkernel _kernel; public static t get<t>() { return _kernel.get<t>(); } public static void initialize(params ininjectmodule[] modules) { if (_kernel == null) { _kernel = new standardkernel(modules); } } }
this solution make use of static servicelocator (the iockernel), regarded anti-pattern, because hides class' dependencies. difficult avoid sort of manual service lookup ui classes, since must have parameterless constructor, , cannot control instantiation anyway, cannot inject vm. @ least way allows test vm in isolation, business logic is.
if has better way, please share.
edit: lucky likey provided answer rid of static service locator, letting ninject instantiate ui classes. details of answer can seen here
Comments
Post a Comment