Dependency Injection in WPF - A TimCo Retail Manager Video

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
welcome to another video in a tIMCO retail manager course this course focuses on real-world application development this is a series so the way they get the most out of it is to start at the beginning and watch through an order there's a playlist set up for that however if you're just interested in the topic this video covers that's fine to think of a series like a bunch of Lego bricks each is valuable on their own but seeing them put together is even more valuable now in this video we're gonna continue working on our day opf user interface by adding in dependency injection now if you're a patreon supporter at the $5 per month level or higher make sure you head over to get the latest source code and let's get started now normally when I do dependency injection I use a tool called auto FAQ now I find that auto FAQ is really powerful and yet simple to use but with Caliburn micro it already brings in with it a a depends injection system called simple container so instead of trying to force a lot of fact onto this or get another plug-in try to make it work I don't use a simple container because simple container is simple and it does everything I needed to do and I don't want to go as far as to go to the next level of Caliburn micro which is actually meth which allows for some pretty cool stuff but it gets a lot more complicated surest stick with simple container for now if we have to later we'll swap it out but I think this will be all they really need so what is up it's fairly simple as a name implies private simple container will call it container equals new simple container so this will be our container which if you're not familiar with dependency injection what's going to do is it's going to handle the instantiation of all of our classes or most of them and this is actually a point some people get confused on in that they think that once you have dependency injection you can never new up an instance and that's not really true there are times especially the biggest one is data models so if you have say dapper loading data from a database I don't go to depend Z injections they give me a new instance for every row in the table I just give dapper the actual model and yes that creates a dependency but I'm already depending on that I'm not going to swap that data container out for a different day container especially since I don't put logic in my data containers so we'll see a little bit more that later on but just know that there are exceptions to the everything gets moved up through your container okay so this container though is going to do most of the work where you'd normally see equals new something like like right here that instantiation that won't happen very often or application from now on because the container will do it for us so now we need to override a few different things so let's go protected override and say get instance and in here we're gonna say a returned container dot get instance service key most does is observe yes what this does is they pass a head type and a name we go ahead and get that instance well in this case we're going to say let's get from a container instead so normally Caliburn micro uses the conventions finds the location and creates the new instance of for example the shell view model well instead we're gonna use a container to get that shell viewmodel we also need to override so protected override and this is get all instances and in here we need to return underscore container dot get all instances of that service so again same thing were you asking for all instances of something we're gonna get all instance of it basically a ienumerable of whatever type they return and finally we need to do a protected override on the build up this is where it basically constructs things in this case we're gonna say container dot build up on our instance now if Sons confuses you don't worry pretty much this is copy paste so take my code put in your code and it works you don't have to touch it now I do recommend that you try and follow through was doing and understand why it's doing it because whenever you have magic sections of code and they break you're up a creek you don't understand the magic in the first place so you can't fix the magic when it's broken so I do recommend you understand it but this really isn't something here have a spent a lot of time on or do a lot of configuration for so those are the four kind of simple ones for our our setup we have one more and this is the one that maybe you're looking at this and saying well where does the actual instantiation happen or where does the container know what to connect to what and that's where we have to configure method and I actually usually put this right below the constructor because this is the most important one I think and so it's where I want to see wrap front so protected override and this is the configure method and here we do is we say container instance on its core container what that's going to do is whenever you ask for a simple container instance they'll return this instance to you so it's kind of a little bit meta here the container holds an instance of itself to pass out when people ask for simple container the reason for that is because we may want to get this container in order to manipulate something or change something or to get information out of it besides from our constructor so as to start next there's a couple of things that we need to add that are based in calibre and micro that we're gonna use so container dot and this is a the format I've seen calibre and micro do and so I'm gonna do the same because it kind of makes sense and it also helps it be a little more readable so I hit enter and then do dot down here now for c-sharp he doesn't care if you have this line break here no big deal all it cares about is where's my semicolon that denotes the end of a line so as long as you wait to put the semicolon it's cool we'll just keep you know multiple lines so singleton I window manager is window manager and open closed parens and then hit enter and dot singleton I event aggregator is event aggregator so what is this doing well there's two different things that caliber and micro uses that I want and there many more later but for now these are the two that stuck out to me as important from all the extra stuff caliber micro gives us the first one is the window manager so handling the idea of bringing windows in and out that's pretty important and the other one is the event aggregator so this is where we can pass event messaging throughout our application so one piece can raise an event and different piece can listen for it and do something with that event essentially it's how a tire application together instead of passing data back and forth through constructors and public methods so we have an event our gear that handles it for us central clearinghouse for all events so those two things I want to come through but for both of these they're Singleton's now if you're not familiar thing --gel ttan what it is is we create one instance of the class for the life of the application or in this case for the scope of this container which is the same thing as the entire application what that does is then if the shell view model asks for an I wind or I event irrigator let's say it's gonna get back the event the first event our heater ever created if a different view model asks for an event ie event aggregator that view mail is gonna get the same event aggregator as shell view model because we only have one instance for our application that's a singleton it's almost like a static class but not quite so that's and the reason for that is think that this way we're gonna connect two events would it make sense to of different instances with different events in them and then have this thing we're basically no one's talking to each other because your event that you want is in one instance and the event that you subscribe to it in a different instance and so you never talk to each other news be a mess so one central clearinghouse one event aggregator and every connect to it same the window manager we don't want windows open in five different instances and not displaying because there's not in the right instance so we have one instance so there's Singleton's typically your application should be very careful not to use Singleton's unless you know for sure you should it's one of those design patterns that people often want me to teach on and I'm going to at some point but the danger about a singleton it'll you'll learn about it you want to use it and really the best advice is don't use it unless you can't find a better way and work really hard first because Singleton's aren't typically great on memory usage and they're not great on the overall using object-oriented the way it's supposed to be used so just that note of caution don't make everything of singleton in general you want the per request which is basically a new instance each time create the instance use the instance throw it away okay so now we have our two events or our two interfaces registered so the first one's the interface this is what asked for will ask for an eye window manager and we do will get whatever this instance creates so a new window manager a new event aggregator for eye event aggregator this ties the interface to the implementation now we need to handle one more big set and that is all of our view models that connect to our how you wired those up well we say weed a little bit of reflection which if you're familiar reflection it's one of those tools is really powerful and we say almost always don't use it because it's slow and slow is a relative term it's not slow like if you do it once you'll see a noticeable difference but if you do it ten thousand times sure you'll see a difference it's kind of like adding strings together it's just fine add strings together but if you're gonna do it ten thousand times don't use a string builder instead so in this case where I use reflection but this configure gets run once at the beginning of the application so there is a small performance hit on startup but when I say small it's tiny and it happens once and not again so we're not going to worry about this performance hit this is a good use of reflection sorry I say get type dot assembly dot get types I come down the next line is the thing it long dot where type and the arrow function or the lambda expression type dot is class so we're going over a statement run done type you might want to kind of go through it first and type it out dot where type our arrow function again type dot name dot ends with viewmodel you see we're going here dot to what's with this next line dot to list dot for each view model type our arrow function underscore container dot register per request so every time you ask for it it's gonna give us a new instance open our parens and inside here we're going to say view model type comma view model type dot to string and view model type the very anti semicolon so what I do well I said where I use the reflection get type for our current instance so this is okay let me say the current assembly that's running you get all the types so it's gonna say get everything every type in our entire application we said well actually where I'll limit that which is the where Clause here Calacanis in sequel and say only where a type is a class it's only class types for a limit further and say where the type the of the name of the class so the name of this class ends with view model South layer that's this right here shell view model all of our view models and in view model that makes it very very easy then to say well give us all the classes the end and view model when they do take that list and print out or create a list this returns a ienumerable which we can't use a for each on but two lists helps us because now i can do work on this list particularly they for each it's ready to a for each on every class that we've found the ends and view model in this case only one of them but in the future we more and it's going to automatically add more because it finds everything with view model so it's gonna say okay I want you to take my container and register per request so this is for each so when it finds shell viewmodel it's gonna bring it in here it's a container dot register per request shell view model shell view mouths name and then she'll view model again and that's the format of type key type it's service and implementation so the idea here is if we wanted to we could have the first one be our interface like this one is and the second one be our implementation but we're not going to do that for our view models right create we're not going to create interfaces just to create interfaces so instead what we'll do is we'll just have it wire up the actual class the view models now yes this may make it a little harder to unit tests in which case we may come back here and change this over to an interface but for starting out I think that wiring directly to our class type is fine so we'll start there we can expand more right to an unit test and say yeah we need to do that we can go ahead and create interfaces and wire to that so I'm planning for the future and I'm planning for the fact that this will change at some point but no worries because that's just changing this code right here it's not really changing a lot other than adding interfaces as well for our view models and so I can look to the future and say I want to do that but I'm not unit testing now so there's not wait for me to do all this extra work just to get off the ground when I'm not going to use it now that's not a big change later so I'll leave it for later if I need it so I'm trying not to over engineer this to the point where it takes weeks to get a application array to start we're trying to get it started so that's around it we're going to just go ahead and wired up just based off the type itself so that being said when you make sure this works because we have changed a whole lot we actually added a dependency injection system that's kind of built in a caliber and micro but we configured it and we're not quite sure is it going to work the way we expect it to is there bugs or problems let's find out if it's tart and it started now notice that startup process didn't take any longer than previous times so it's not like we have anything big going on yet now I don't have a whole lot of shell view models and other view models to search through but reflection didn't take an awful lot let's put it that way so it still runs and it seems like nothing else has changed so hitter I do I'm actually at this point going to commit my code because they have working code that I believe is correct so come here and go to synchronize go it changes and there's a lot to have that's changed in let's review it makes sure that we know what's going on we've added basically everything in the desktop UI project and also the solution that sounds about right but let's make sure that all the files we've added are correct and they appear to be I don't see anything here that's that stands out to me as not in the right place or not the right file to add so let's go ahead and add all of these we're out right click and say stage and now rest say add WPF project with mvvm adds our jpf user interface project and configures its with Caliburn micro for our mvvm framework also includes the simple container deai system okay they hit commit staged but that's it I'm not gonna push it yet like I hit sink or push it up I want to wait for a minute now the one thing a previous lesson I didn't mention but I don't know if you noticed or not I do not come to this and point this out just in case you you wondered why or wondered what's going on in our data project under published locations we can zoom in here there is a red circle with a line through it next to our trm data published XML file they may wonder what that is that's yet telling us that it's ignoring this file and the reason why is we don't typically want to publish publish settings we want to put those in the github because those might contain sensitive information like usernames and passwords so just know that's not getting pushed up by default and I'm okay with that that means I can use it locally but when you pull it down from github if we're going to do that then you would get an empty actually we didn't get this published locations folder so then you could create your own published locations folder put your own publish profiles in there and I wouldn't get them because I'm not publishing to your sequel server you're not posting to mine therefore it's a good thing we're not sharing so let's kind of note that when you're looking through reviewing your files do look at those icons to tell us tell you what's going on okay so now we have this committed and all of our we have no changes left on the tree that's correct yep no changes now I'm gonna make a change that I don't want to keep I want to try something out I know I'm not gonna keep the code I just want make sure that my pensee injection is actually working correctly so I'm gonna do is create a class I'm gonna put it into Tappan Zee injection I may even create an interface for it and then I'm going to ask for it in the shell view model okay so all this code is just dummy code to make sure that depends the injection truly is working the way I intend it to I don't want to keep the code though with a get I don't have to worry I've committed my latest changes so I'm fresh I don't have anything in my stage or in my working directory therefore I can just start making changes so let's do that right clicking the project and say add class let's call it calculations this is a pretty simple class I create sometimes let's create a list string that is register initialize this it'll create a public public void no public double add double X double Y return X plus y there we go and now I have both a property and a method now let's go ahead and create an interface for this like click on my class name hit ctrl dot and say extract interface and is hit OK for the defaults which are going to be fine for me just it checks all the public methods and properties calls it by the name of the class with an I in front of it then puts in the same folder which is cool so now I have an interface I calculations that has my register and my add and now calculation implements I calculations so cool I have something to work with now I can come over to my bootstrap RCS come right down here and I'm gonna want one instance per request so let's say container dot oops per request so it's gonna get one per request must say I calculations calculations so what this is gonna do is going to register my I calculations interface as what will be asked for and when that's asked for it returns calculations this instance per requests therefore if you request in five different view models the I calculations you get five different instances of the calculations class now in my shell view model let's create a private I calculations call it calculations I'll create a constructor ctor that's going to ask for an eye calculation call it calculations no underscore and then say that underscore our calculations equals calculations so what's going to happen is she'll view model is saying I want you to give me when you create me want you to give me an eye calculations instance so whatever implements eye calculation and give that to me a new instance of it and put it in this variable this parameter where I take that parameter and store it in a private variable on this instance called underscore calculations in theory that's all we have to do register our instance and our interface that talks about or talks about it and then bring it in in a constructor so I map and I break point right here gonna save everything I'm gonna run this and when it starts up it's a pause at this breakpoint because remember this is the start of our application is a shell view model so let's look at the calculations parameter and if we zoom in here it says calculations register count equals zero so what is that saying well it's saying only has one property called register that property has zero items in it so that is our instance of in this case trm desktop UI dot calculations so it's create an instance for us and passed it into our shell view model so we're all good our dependency injection system is just that simple whenever we create a new class you want to add we just register it here and tell either a singleton or per request and then we also just ask for it then in our constructor that's it so now we have a sample code in it's working that's great but I want to revert all of this and it used to be they'd have to go ahead and delete different things but notice up here my project changed do you know how to revert the project well you don't have to thankfully because we're using it so instead of deleting things and and trying to manually back things out go rat teen Explorer there are five files have changed we've updated shell view model we've updated bootstrapper and we've added calculations and I calculations and we've updated our project but if you highlight the files that you want to undo the changes in right click and say undo changes it's gonna say are you sure because you're gonna basically delete these delete these two adds and you're going to delete the changes in the other three yep as I want to do do that and now there's two more files that's the adds it doesn't undo them there's nothing to undo them to but we can do is say delete since they're add we can delete them and say you're really sure we say yes now there's no more changes it's just like it was before I started testing I've wiped out all my changes now I could have gone create a branch done my work check back in a master daliyah the branch and that works as well but again I'm something similarly a small environment just just me so doing that little bit of stuff not a big deal but if I was gonna do some work a little bit longer yes I'd create a branch first and then do my work then check out the branch and either delete the branch or leave it sit there just as a reminder in case I had to go back to it but for now that's it we're done so we have created our WPF application we've add mvvm with calibre and micro and we have wired it all up and they've also made sure you wired up our simple container system for dependency injection in our next video we will set up our class libraries so we have a place to put our data access layers for now thanks for watching as always I am Tim quarry [Music] you [Music]
Info
Channel: IAmTimCorey
Views: 47,642
Rating: undefined out of 5
Keywords: .net, C#, Visual Studio, code, programming, tutorial, course, training, how to, tim corey, C# course, C# training, C# tutorial, C# app start to finish, timco, timco retail manager, wpf, asp.net, .net core, asp.net mvc, autofac, c# solid, c# solid principles, dependency injection, tdd, unit testing, xunit, moq, caliburn micro, mvvm c#, mvvm, xaml, xaml c# tutorial, dependency injection c#, caliburn micro dependency injection, simple container, c# simple container
Id: Q5ciBOoMt8U
Channel Id: undefined
Length: 33min 1sec (1981 seconds)
Published: Wed Feb 06 2019
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.