C# WPF UI Tutorials: 03 - View Model MVVM Basics

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] so in the last video we created this tree view and basically acts as like a mini file browser and mimics the folder structure on your machine so we're going to use this as an example to convert to a basic view model so we have all the logic right now in the actual UI so this is a class for the actual WPF UI and we've got you know in the window loads which queries your logical drives and we specifically create this tree view item which is the UI element then we add it and then we cook into UI events to then do things so this is very hardwired into the actual WPF application so that means that we went to a movie two windows forms or we wanted to make this an android app or an iOS app a little and except for anything other than a WPF up all of this logic and all of this expansion and everything we do here it'd have to be completely redone it's as good as useless because it's hardwired to a UI so the point of view models is to separate the logic like actually get in the folders and figuring out what the data is and whether it's a folder or a file or a drive and all that type of information that becomes your data and then you want the view model that then links that data and converts it into something that can then work with UI without knowing about the specific UI as well and then the final step is to bind the view to the view model so it's much easier to show so the first thing we need to do is strip all this out and get it into its own classes so we'll just make a new folder in the project just call it a directory because that's where all the directory stuff's going to go I'm going to create a new class call it a directory structure and this is just going to be like a static helper class that's going to contain all the information for query in the directory and just generally getting information so a helper plus to query information about directories this is whether the real data logic is going to happen and then we're going create a folder called data for now again this would usually be in separate solutions or so separate projects where your concerns are in different locations so this is the UI then you have this in another project and you need separate things but for the small one it doesn't matter we'll just dump it in here and then we want basically want to create a data model for a directory item we'll call it so basically like a file a fold of a drive and anything that can be contained in a directory or the you know the folder itself the drive itself so information about the directory items such as they drive file or a folder and this class is pretty simple there's just going to be a name just do that a second we've got the full path that's really all the list to it for the most part so that's the path for the item the name we can then use this helper function that we already made right now it's just in in a few I so let's move that out so we've got this helper especially just cut the whole thing go to the UI and move it to the directory structure add a little helper here I can all stay the same get file folder name so we'll just want a guest here and it's a directory structure correct a namespace get file folder name of the full path so there's no need to specify the name because the name is always going to be effectively this so that's the name and if you remember we did some logic somewhere we're doing this on a drive resulting in a blank string I think it was in the header item yes I like here which activates a blank string so we know the name really of a drive wants to be the full path Excel wants to be the drive so in order to obviously know about a directory up as well we need to type so let's just create another class and it's going to be any numerator this time we'll call it directories I can cite I think and then this is going to be a numerator and we've got a drive file on a folder let me know off a logical Drive physical file a folder so now we want a directory I can tax as well and that's really it so that's now a data object if you will that's pure data about a directory item so when we query all of the information this is what we want to buy each item we want the full path the name and what type it is and that's enough so guard directory item will go directly I'd some type and then the structure now in all that for now we go back to this class and we start at the top so when the window is loaded we do this to get a logical drive and then we we do all this UI binding which we won't need so let's just cut this first and we can even get rid of the window loaded because you won't do anything unloaded now delete the loaded from here and then in directory structure one of the first things you want to do is to be able to get the logical drives so a lot of a public static list the directory item we just created get logical drives and that'll be like to start a point paste that code in we now want to do we can really shorten this because this is UI item that we don't want to tree view item so that can all go so we don't need to add we don't need to listen to expand we don't need the folder to be added there we also don't need to do a for teach now so this becomes really simple what we need to do is return a new list of the directory item in fact don't do it that way so what we want to do is the logical drive and let's select to cast it to a directory item so just do the drive we want to convert that to a new well convert each one to a new directory item and then we just need to specify the full path is the will drive itself I spelt it wrong that and the tie is a drive then we want to just convert that to a lift and that's that function done special return then a list of directory items based on this information here so that's now a much easier function you'll end up with a directory item for each one with the full path be in the drive and the tight being drive oh it's just that reminds me let's correct this so now we know the type if it's a drive we want the name to be the full path not the folder name otherwise it will be blank so let's just do that so this dot type is a drive then you want it to be the full path otherwise you want it to be the folders that'll do that so get some logical drives on the computer let's get that content and then get rid of the unloading now minimize that the next thing is when folders expand we basically then get this the sub content to the folder so these checks can go because the view models going to handle all this type of thing so all that can go and then really you're getting the folders and the files so let's cross all of this which then becomes the rest of that function get rid of that function as well so you can now see already the UI's got nothing in and then we need a helper at night how do we need another function and this which is going to do the same thing it's going to be a directory item and we'll call it get directory contents and this will let me turn the files and the folders I want to pass in the full path I've seen of contents again that's the directory's top-level content the full path the content up to the directory just take that in for now and then what we want to change we know we want a list of directory items so create the list and then for the get folders now we don't need to create this list now just strings because we've got a rectory item let's get rid of that and then the try you still want to get the directories but now instead of directories adding range you want it to be the items and then instead of adding just string we need to do same as we did with the last one we need to do cast the directories from what they off to a directory item so for each item in there we'll create a new directory item and that work there and then you need to set the full path to the directory and the type to folder and that's it for that this is that all UI stuff again so this was creating a tree view setting the data adding a blank item all that can go again because we're not interested in that now we're just literally asking for you know a set of directory information and then we do the same for the files so that goes and then we've got the files is now the items this UI stuff here goes and then we will return the items and then we also need to cut the files to the same thing so a new directory item whole path is a file the tie is a file and that's really at you've that's the whole thing that I'll now get the contents and return a list of directory item so that's already simplified and I think that really makes up the whole directory structures all you need to do to get data and then you're going to get a list of directory items based on you know in your logical drives are going to be directory item so you can get the logical drives as a list you can get the directory contents as a waste so now these two things are ideal to start working with the treeview so this would be like the first list and then each one inside is called get directory contents but obviously when you start doing that that becomes the UI you don't mix this with the UI so this is where the view models come into play now this is where you need the the bridge gap if you will between the data and the view and that's what the view model does so we'll create the view model now you're going to need one for this directory item so it's create another folder in here pulled new models and then we'll create another class and we'll call it directory item view model and so people get concerned with view models and these things are complicated and linking in a you know model with a view is really complicated it's not so the simplest thing for a view model let's just see if I can compile first just change this to directory structure we'll let's compile yes we can compile so we just go to this view quickly just hook this in a stackpanel cut that out move on to there it's just out of button and some content so the default content is test their name for that and part we don't need a name so the way view models work is you buy miss this object in UI to an object of view model so then it gets the content for it so instead of finding you know specific elements here like the actual UI and going to the tags from stuff you literally refined directly to your content so all the view model is we just create a new class I just literally call it class one so this whole thing to make a view model you just have a class like annular class you just implement the I notify property changed interface and that's it so that now is a view model so we have to create the actual the event itself because this is what it's fires and that's it that's now a view model that's all you have to do and all the view does say we now bind to this class because this is our view model so in the window yes the window and the constructor the data context is the root of the UI in terms of data binding so if I set this data context to MU plus one now in the view instead of being text if I do content is the binding that's going to bind the content to plus one and by default because content will try and display a string it's going to do class one dot two strings which you'll just convert to I'm guessing WPF preview plus one or something which it does so it's already bound to this object so if we just over either to string and we could just return hollow will proving that were bound to this object and that's what's happening so you can see there were data bound now you don't usually bind to the actual view model itself design to properties on it so the meta property called test and if we just to get and set and we set it to my property and we actually change the binding to buy into the actual inner element called tasks you can see we get my property so it's already a view model now the thing with this property changes when you bind here and you do this test this content is now not only binding at the time of it load in the initial binding but it's then hooking in to this interface and listening at this event and it's waiting for you to say that this property the main test has changed and then at that point it will go and refresh this property on the control so if we went to to the class or just in the class itself will make it sort of self aware we'll just run a new task it's completely just for a demo just to show you what's going on but also to show you just how easy view one of our there's nothing complicated there and then I'm just going to do again this is don't do this in the real world this is purely a demo which is no loop forever we're going to wait for a fifth of a second and we're going to keep an integer and we're just going to set proxy test equals an incrementing integer so basically have we every five times a second the test value is going to change you can break Quintus it's kind of change to zero one two three six zero it's my property now and it's zero and it's one so if you run this you'll see that nothing's changing here to still my property the point of view models is whenever you change your property you views meant to update and the trick is what you've got to do you can't just do this you can and I'll show you how in you know after this video the end of this video I'll show you how to do just this but all these looking out for you to tell if the properties changed so one way you could say here he literally just call okay the properties changed so I'm going to call myself it's this element and the property test has changed this is going to fire this event and it's going to pass in test as the properties change this is actually going to tell the UI that that has been changed now if we run that should work you can see now it's bound to the UI properly and all we need to do that in anywhere in code is to change the string and the UI will reflect that information now you don't usually do this here this property changed here you want it to happen automatically when you're working with a view model you just want to set test and it should work so the trick is here you move this into this property so now you've gotta change it to an actual get a setter because we're doing custom code so now we need a private backing field or just call em tests so we just return em test that's just standard property that's just how they work and if the test hasn't changed so the value hasn't changed just return so you set test to the exact same value there's no point in doing anything else if we get here then we've changed then we do and test equal the new value and then in here we tell it the property's changed and then we can make this nice you don't want to hand type test because then I'm I rename this to test too this is them wrong so you can just do name of test two and that'll then turn it to a string of test two and then if we go and rename this in code that's always going to be the same thing so this sort of setup now is a self aware property so all we do is set the value here and now the UI should update automatically and that's it that is effectively a view model that as a whole point of a view model that in your code all just have to do is bind to a value in the view and then in some non view stuff so anywhere in code you can then just get this whatever property you set is the view model here whatever this is this can be anywhere in code you can then just directly change the values on it and it will automatically reflect in the UI so it keeps the thing setting this value is completely unaware of the UI yet it will work in the UI so a view model is nothing more than a that implements I property notify changed and then it should fire this property changed whenever you know a property's value has changed like in this instance and this is a default way to do that as to for each property to write this out now it's going to do this at the end of the video but I might as well doing now so just so you're aware that this is this is what's happening there's no magic going on you set a property and then inside the property we call this event and tell the universe event to fire saying that we change that's how it works now instead I'm going to write this for every property which gets really tedious and annoying you can go back to this and you'll see this won't work now because there's nothing firing that property changed well there's a little helper so we right click on references and add new get packages and then browse maybe you tied for the property changed think it's called and their property change body click install just accept the license this is going to add this really useful add in here called fadi Weaver and as the federal XML team project that basically just tells it to include it this property changed and that's now added this body Weaver so all you have to do on the actual view model is say implement property changed and this little attribute here when we compile the code now if we had done that reflector I could show you but now if we compiled well when we do compile this code this fadi Weaver is going to pick up the actual compiled toes so there's normal property and then because it's tagged here it's going to find all properties or all public properties on the class it's going to smartly detect when the beam is like if this is related to something else like when this changes it sets another value it's really intelligent it figures out you know if you change this what are the proxies you change in the class it works out the whole thing and then it goes and injects their call to property changed for you so it figures out the the default code that we have to do to fire every time we change this we have to fire this and pass on the name this fatty Weaver after the codes compiled goes and then converts the the pre-compiled bit the IL code and inject these calls property changed so it effectively does that for you so as long as you've got this implement property change on your class and you've got public properties it will fire this property changed for you and you can see that by just going into this function point and breakpoints a and if we compile now so the only difference is we've added this employment property changed when we change the value so we'll run and we're about to change we run and you can see it's now fired that's property changed for us and the property that's changed and I could get v go over it test so that's funny Weaver that's what is done there we've called set but this set if we went into the actual IR code which I think we can step into some way go to disassembly maybe they're not disassembly maybe go to source now okay so it's easy with dotnet reflector I'll show you in another video but what's happened is this setter is now as we wrote it before so if we undid the code went back to how it was written before you'd see that this Foley Weaver's done that for us so it just means now we can just write a public property as if it's a normal property and because this is tagged you know what's happening it's just calling this property changed for us so that's your view model and as you can see you don't need that now and you don't even need this this is just changing the code so there is your for view model it's a notified property changed there is just a box standard blank function because we don't need to do anything specifically this is just an event and then you put the properties on so effectively it's a normal class just with this and this tag done and that's it that's a view model and so we'll get more into that now as we make them but hopefully that's made you realize there's no little magic going on with you models there's nothing hard you are what they are they're pretty simple you just got a bear in mind that the view basically hooked into that property then the parent of that property it hooks into the IOT fire change to listen to that event to fire and if it matches the name of this path it will then go and ask for the new data and then I'll date the UI itself that's that's what the bindings are doing so take this back to what we were at and then we'll just carry on and will now make a view model so delete that class so we've got the directory we start with this view model directory as a view model and it'd be a good time to now make a base view model and the base view model is just going to implement that Holly Weaver attribute and do the property changed event for us so just saves us doing that for every view model so it's a base view models and I notify changed and notify property change to complain to the name then and we also want a class to implement property changed this wants to be sender give them there's a blank one this is now base view model fires property changed event as needed the event is fired and any child property changes its value so it's pretty simple base view model that's what we've just done in the last one and this is a view model for each directory item and then we want in this directory view model and we'll have the full path again so we just want a public string full path we need a name again just the same oops that wants to be directly shared dot now that do which is that right actually yeah I like to do that same logic that's in data that's all just copy that that's exactly the same so you'll see you with Keating parts of the data in here but that's fine because this is you only include information here that you need inside your view so the view need to know about a few the full path and the name and then we'll actually need this type so don't give up but in here as well and you'll see in a minute why we you know we've got all the items repeating but we've also got additional things coming so we've got the type then that's required for knowing what icon we show and then you've got to also have now an option for if you can expand for one so the items in the view the the little dropdowns you need to know whether they can expand or not which actually I don't know windup binding this because that's that's worked out based on it this children in the list in this both while addict anyway because again for other you is it would be useful so can expand and before we can do the expand you needs children as well so this is a directory item so it could be like a logical drive and then it needs its own children to in order to step down and drill down further so you can use it on the list but in view models you tend to use an observable collection which again is just a list that has another I notified collection changed event so that any view models any UI listening out on lists or less melt for this collection changed and when this fires it then rebinding is a list item so it's again it's like a view model thing it's it's a collection they're the only two is the notified property changes and the notifies you know a collection has changed so this is just a list basically it's just a list that fires a collection changed whenever you Adam remove items that's always a lot of observable collections are basically a list of directory item view model and this is the children especially edge it you know a self occurring unless this is the item and then it's got children of itself you know the same type and stuff the children is mopping again nothing special about that can expand we want to expand if the basically list type isn't equal to a file so we're driving a folder can expand and a file can't so indicate of this arson can be expanded list of all children in this item nothing really summarized first of all children contingent aside their size or something like that's the can expand then you can see now we're adding UI specific things here to the directory so we're directory doesn't care about you know can expand it's got nothing to do with the directory this is purely a UI things this is where the view model comes into its own where you start adding UI specific things we also want to know if it's already expanded because the view when you clicking the little expanding icon this thing here when you're clicking this to expand when you click that the UI is saying well I'm a expanded no okay so I need to expand so it then sets that is expanded so you'll find out that when you click this arrow the UI itself or then set if we bind it to it will set this is expanded property so we want this to be a guess and a set so the guess is when the UI is going to ask you it is expanded or not and we're going to say say nope so it will show this when we click the UI DUI is then going to call the set and say that and will be now needs to be set to expand it because we've expanded so we want to know if it's expanded so we're going to add a dummy action still so we have like a no litem too so we can show that icon so we need to find the children and make sure we've got some first of the question mark and get account should be able to or when concluded we want the count of the children but we only want children that aren't equal to null and because obviously null is going to be the dummy item so if we have any children on no so basically we have any children then we'll expand it because we've got children in the list and that's how it's going to work then it will not expanded and the UI tells us that we want to be expanded we then need to actually expand so first you do the normal check if the value is true so this is the UI scene right I've expanded you need to now actually expand so we'll create a function called expand so I'll turn them in down here expand this directory and find all children so if the UI tells us to expand my little children and then if it's not so the UI then tells us to close that's really simple we just want to remove the children so we'll just make a function list clear children they'll make another little function here and that will just set desktop children is a new list I stop children as a new list there's all children from the list adding a dummy item to show the spun icon if required so we clear all the children but we also got a bear in mind for directories I like for folders and drives we need to show the expandable icon this arrow here and to do that we need to have at least an item in the list so we need analyte them but only if it's a directory or a drive so so they expand arrow if we are not a file so if a sub-site that isn't equal to file then just do this stock chosen to add no so this will always have a no litem for those and then this has expanded we'll also be correct so if it's if it's got you know who's got an item it's got a child it won't show because it's going to check first that it's not know so this is expanded or match as well and be correct so see has expanded we can now clear children as a helper function helper method to clear the children these are public properties and you can see how this is more work than the previous way of doing things but what you've got to bear in mind once you've done this now is this directory item view model and the whole structure that we'll do in a minute this is completely cross-platform so you can then take this to Android to iOS to Linux to even on Windows you can just redo the UI the whole logic about how your program works the thing about finding files and creating the structure has now gone here completely and it's even UI aware he knows that he expects it to expand owner so to then change your UI becomes really easy to just reuse the logic becomes really easy it's completely separated to concerns so your data is just back it just gets you know get logical drives just gets that there's no blow to just get the information the directories gets the information so you've completely separated all the parts of the code and kept them clean and really small individual chunks are doing specific tasks so this is a lot more work upfront but as you see the more you build programs and the more they get complicated this really is the benefit of your code is completely portable can be used cross-platform you can change the UI and much easier there's no you know hard ties in the background so it looks like a lot of work but like I said this is a much better way of doing things and you'll see the more you go what the benefits of doing this are so they're the public properties now you also have in view models instead of having functions like this so you still have a function but for the UI to call a function you don't tend to have function you have a command and again it's basically just a function but a command you want to like on a button so if you've got a button on the UI because the button is just that you can click it and it will do something no button on here but you know what a button looks like when you click the button you'd want it to run a command and it's got to be a single command with no arguments because that's just what you should do in a view model the view model self aware it shouldn't have you know things packed into it it should be self aware based on its own properties so you want commands as well and think of commands just as functions and we need to create a little helper here so you you've got a command and it's callback command and then we'll call this the expand command and then to expand this item and now in order to run we need to create a type of command and we just want to run a function so we'll just create this little really basic thing we'll just call it a I'll just call every lakum and it's just going to relay the action meaning to a command it's just doing what it's doing so it's just create as well relay commands first and that is just going to be of almost junk again this is just something that's going to run an action as simple as that has not been something magical going on here so we're going to implement the I command and let's see what that entails so connect click you've changed it's just me event handler so sanguine event will just create a blank function below was that expecting a return value that's quite a be that so that is your blank the event that's five when II can execute which sub function and execute method by it changed so can execute what a function so in this case we just want to return through and that's how you do that and you can inline a function nice and easy somehow see if I can get the syntax Rach now okay well I know there's a way to really quickly inline a function I really want to do it now I know there's a way of doing it l did on the next video so let's just do a normal function for now so I really command can always execute so that's just there that basically says like so you bind to a button you bind a command to a button that can execute as what will make the button be the grayed out like on clickable like these or whether it's available so this can execute is basically saying can I do something and if a button can't do something then it doesn't allow you to click it but in our this basic just you know relay command we just wanted to run a function we're just saying we can always execute such as roughly as off and then constructor we want to pass in an action so something to run we need to store that so an action is just a basically a function with no parameters and no return value just as a plain action you can do actions that pass in parameters but think of this is just a blank function like this executes but with nothing in there just as literally just a function like that so call it M action and then when we pass that in we set it here so you can now construct a relay command and you just pass in an action just the action to run and then these are finally the command methods so then the execute just simply wants to run the the action with us then so that's it that's all what's going to do so this is now an I command that we combined and the relay command will simply run whatever function we pass in the constructor it's just as simple as that so unless we need a constructor as well and then in the constructor we need to set the expand method so spank man equals a new relay command and we just pass in expand the function we've already made and that's it so now that's now a command that we combine to in the UI that then calls this function so now we need to actually fill out this function to do something so the expand is going to do I think we deleted it enough I don't think I've got it in code anymore but we can redo it so this is when you've got a drive and you click to expand it so what you want to do is firstly a file can't expand so we just want to make sure we're not a file we shouldn't ever be but we'll just add back yet so as I start to type this file return we can I expand the file and then we now just need to set the children to the new data and we've already done that's why we did the work in this directory structure so the children is just directory structure don't get directory contents and it's the full path and that's it so now we've got a list of all the directory contents and it's a directory item or we need to set it to a directory item view model so we need to first do a select again and we need to cast a content to a new directory I can view model and I've got this needs to be a lot to set the the full pattern the type so on string for path all right time I'll pass on this item item set them all and the reason I'm doing these inside a constructor this time it's because we've made made this helper function clear children and we want to add this child if the type it isn't the file and then as you'll see from how the code will run if we specify this type afterwards after creating it then this can get called before we set the type and it can invalidly add children to you know a type that is actually a file so we just make sure that the type set straight away how generally other thing we need to pass in is the type but we might as well then just pass in the full pattern type so close the entire thing down so the children equals I want to be this new directory I can view model it's simply the contents full path and the content type so that gets us to there and then we want this needs to be an observable collection on our list so it's just a new observable collection and there goes a single line now so we basically say when you expand find all children and you can find it easy you could split this down if you want it to be you know not just a single line it you could do like children equals the get directory content and then you make a new observable collection from the children and you're basically casting the children to a directory out and view model so that's all you're doing there starts the expand them and we've got now a view model for each item another final thing we need I think to piece this together is the actual the view model for the whole thing to keep it you know a list of these items so let's make one more time yes perfect please make one more view model and this is going to be the view model for this actual view now that the tree view itself but you know the view of the whole directory so we're going to call this directory structure view model get rid of all the crap make it a base view model the view models or the applications mean directory view and this one is going to be really simple so we have a probably of preservable collection which is again with just a list of directory item view model and this is the accent so a list of all divert Therese on the machine so this is effectively going to be the logical drives and that's what that's what we want it to be and so we need a constructor so on a slide either so and then when we create the view model that the main overall view we want to set the items to be again a new observable collection and we want map to be the directory structure get logical drives and then we need to select them and just as we've done all the others basically cast them to the view model so we'll move this out to children to keep it a little bit shorter and then create the view of models from the data so this is going to be children dot select and drive when we want to be a new directory I can view model and then that's just going to be the drive full path from the tag is a drive there we go and I think we're basically there so we just go hook up the UI to this and the beauty of this is we can actually test this works without hooking up to the UI first every wanted so let's just go to the view when lights in here let's just create a new directory structure view model and that now should have the item should be the drive so let's just presume we've got one and then we'll tell it to expand so we'll execute the expand command in fact let's do bar item 1 equals d dot item 0 so we're going to inspect and check there's nothing then we'll expand it no parameters in this case and then we'll check it again so if we run this code we're not bound to the UI yet but we just prove in the view model so we get a directory structure we go in it creates a ask for the logical drives which we know works so we get just a bunch of directory items it's got the full path and name and type set but then the items is nothing we then create a collection of them which is now the view model so now we've got the full path the tie is expanded false but can expand because it's a drive and we've got the expand command ready that's a bunch of items so we've got the directory structure view model which has now got items which a few models which are all you know each Drive so we got the first one and you see the first one the C Drive we haven't expanded it yet so there's no children which actually is an issue because we should have should have a single item in there so when we create this item I think we want to or we need to add the know like and we need to clear the children when we create because obviously when you first created that you've then got to add the initial item so we need to go back and in the constructor of this here we just want to clear the children that's why we wanted this tag here and now just do they stop clear children sets of the children as needed so now when we run first child there we go we now got a single null atom and that will allow the UI to then have the expandable icon and we're saying we can expand and then we going to actually tell this first item to expand so we step into it then going to run the action the action to expand it's going to check the type which is a drive so we can expand then you'll ask for the directory contents of that path which it gets which it then creates all these directory items for us and then it's going to cast those two view models just like the last one and now the children have got a load of view models so now this item has now got 28 children of all view models in each view model has got them and again there's nothing that's ready to expand so we also need to do is we want to bind the UI to this directory structure so the initial structure is this so the whole views bound to this so we saw how to do that just do this data context is that so now in our UI everything inside the UI is bound to this class so we're going to be bound to a view model that's only got items to bind to so we now go to the sam'l and then in here we now need to do item source is binding so by default malice binding because the data context where are we because the data context is this binding is referring to this object itself well the treeview wants to be the the items the list a tree views or less died and so you want it to be you know a collection of the each view models so we bind it to items so that's what I'm going to find the data context and look for the property items in their startled now buying the tree view let's just run that and see what happens so you can see now we've got the three items we know they're the three hard drives and now we need to fix the actual the UI because now it's just lids saying you know the name of the view model so we need to change this code and we'll do this a slightly different way so we'll do instead of these resources we will get rid of will keep this because we're now not going to set the head a template will I'll show you a different way of doing this it's a little bit shorter and nicer so get rid of that we want to style because you still want to style the the treeview item it's still going to be a treeview item by default so it's going to be x type is preview item so want to create that style remember on the setter will bind the property is expanded so that when we click the expanded icon if we bind this to our view models so we go now to each item because these items we go to the structure view model each item is going to be of this view model type so now in this this part here what we're buying into because this is per item when our binding to a directory item view model so we're now looking at this class and we want to bind to this property we made called is expanded so that when the UI changes from being collapsed to expanded it fires less event for is it sets our property so to do that we do is expanded and the value is finding to is expanded and by default upping the modes one way so it doesn't bind both ways we want to do to waive which means that if the UI updates it will update our our view model it will take this property and likewise if we set this property it will also update the UI so it goes both ways but mainly so that when the UI updates it will fire this property is expanded here and actually then towers that when to expand here we want to them run the expand function in order to set the children so that sets up the the binding for the years expanded just through a style I'll actually kind of put that right there not missed one step it's got to be the the treeview item container style so that it sets the style of the container if you will which is effectively the thing that hosts to each item so that it will style so that's that's basically the exact same way as what we did previously where we overrode the head of templates but this time we're overriding the the whole template to the item it just looks a bit nice which is also a little bit shorter code and now we want to actually replace the the whole template so this is a style you know the container style not the from the actual the UI so now we want to replace the item template itself the item template is a hierarchical data template and because obviously you've got the item itself which is the tree view like this but it's hierarchical because this item itself has children which is going to be these so a hierarchical data template is at the item which is a tree view item but it knows that it's got to contain children you know these things that expand so we also need to then bind the children to the children here so that then it carries on down the line that then the inner items are bound to that a few models again of the children so this hierarchical d2 template we set the item source just like we've set here so you think of it as like this infinite list that the first ones are bound to the items which are the view models and then their children get bound to the children of that item so that's where this this constant loop goes so this is this class and then this children in the class which are exact type so this is where you get that continual loop so for that you do binding to children and again bear in mind that each item is bound to a data a directory item not to the structure because it's each individual item so that will then bind the children are now inside here we just simply paste the original view we had we now fix the binding here so that I'll now buy into the whole view model this we want to bind it to the name so we now just change the binding to name and then the picture well now we can do this a lot easier so instead of binding and going up to find the tree view item and then doing a tag that I can although you still want convert but now you can just bind to the directory item view models type so this type so there's literally bind to the word type and then if we just go into the header to item converter we're now expecting we're now going to get a directory type so we need to change I get here full path don't need that we don't need that my default will presume an image file that's fine but now we can simply do we know the value is a directory item type because we're bound to the type which is this so we just simply get that from the value and we'll just do a switch on that value and now we can literally do a much cleaner way where every to drive we shut the drive if it's a folder we set the folder and then you return the image that's it so that's our again you can see now how much cleaner that is but even the converter doesn't have to mess with UI specific things you I have a treeview item it's now an actual and it's a normal object so this thing now should have everything works right they should all wrap up and show exactly the same as before so let's see what happens and there we go so we've now got the first list which means this lets convert to work let's just see that so it gets into here the value is a drive yep so that works then they appeared the reason they appeared is because we've got the item source set to items in the background we create the data context of this new view model so the view model gets created it sets the items up here which then effectively calls what we'll call logical drives then we create the list from it that's where the items appear and that's why these items get three items added then the template go to this so I can just stop so there's template then ignoring that bit for now styles the item template binds to the name of the data item view model which works out to the actual name of the drive and then binds to the converter for the image that's where we've got so far now when we click expand because we've got this property as expanded bound to when the treeview item actually expands what we should get is we should hit this is expanded set value here and you'll also see the guess when it gets asked for it so we've run this again this is now the UI asking what the property is asking whether it's expanded owner which will all be no in the first instance and when we click to expand the UI is going to check what it does right now which is not expanded and then it's going to say right I want to set it to true then I want to expand so that's the UI firing off this event so we looked at the call stack then I'll try to you see not seen anything because that's coming from the UI so that's basically the UI firing and sane right I've changed to true so it true we then expand then then the expand we should be a drive which we are get the directory content to the drive which we've already checked this so we've now got 28 children so now this binding here on the template which should be bound to those children should now mean that because we've expanded and the children have now been set here that we should now get a load of inner items that then start this loop over again that we then get new inner items they get the in is expand expanded property bound which kind of replaces that folded I expanded event we made when we hand coded it this sort of replaces that that's how the expanded gets called so we run this now and then you can see getting the other two which we fry actually these are all the inner ones now this is every inner item being asked if it's expanded on ER and you can see there we've now got the expanded menu have also not got the arrow here because the logic to when we clear children hasn't added this blank one if it's a file so we don't get the expandable icon you can actually double click to expand so this is where this will actually come in I think we double click yeah it tries to expand and then we've luckily caught it here so there is all the ways to expand without the arrow so that check is actually prevented that from happening which is good and then obviously you can just keep diving into each directory which goes in or loop does exactly the same thing it's now just a repetitive binding of exactly the same style and that's the view model done and the benefit was again well I guess not the benefit but the beauty of view models is when you're finished you take a look at the UI so this is the UI we've got nothing unloaded we've got just a tree view with a style we bind to the items for the main one the children for the sub and the name in the picture so we've got like one two three four five bindings in the view just simple bindings with statements there's your entire UI you go to the go to the code behind which is this and you've simply bound to a view model that's it that's your entire WPF that's all the ways these two pieces of code and yet when you run it you get this complete working product if you will and a lot of the time even when I do it today if you still get amazed by when you finish how we just work sure like I haven't told it to you know I haven't constructed this view with code and sat there and said when you click this expand this when you do this go there it's a file don't show this it's all done through binding so it's sort of cool to see that you're thinking while I'm gone how is how is this working when I flick this and you have to think about oh yeah because I'm bound here and that then as a consequence goes into my view model and calls the expand which then sets the children which then fire the property changed which then causes the UI to update itself so it's it's a real sort of head twister sometimes to some people how humidors work but now the benefit of this as I've mentioned quite a few times is you can now scrap this UI and all you do is delete this one file here and delete as one line here and now you can go and take this view model and move it to a windows forms application or to android app or an iOS app and all you've got to redo is this tiny tiny bit of binding that's it audiology was buying to the new properties so your codes now much more portable so in a nutshell lots view models it's a very basic introduction but hopefully it's made it clear and obvious what a view model s which is nothing more than as we mentioned go to a base view model it's nothing more than something that overrides aside notified property changed when you bind into the UI again nothing too magical is happening when you bind like here it hooks into the parent of this items which is this itself this directory structure and it lessons out for its property changed event here which we fire when we set the children and then the UI goes in and asks for those children at that point in time so it's all just worked through this property notify changed event and then to get rid of the need to keep writing manual code that calls those property changed we just went on the references manage new book packages and we searched and installed this fadi property changed and then for each view model we just created the base one so ends up to keep doing it we just simply put this tag here and that then fires this forest when we have view models that simply do this so it makes our view models with like playing normal classes so yeah hopefully this has been a good tutorial to show you how to do view model binding without going too complicated and to show you how we've converted an existing working product from a standard way into a view model way and I know it looks more complicated and there's a lot more files but trust me this is much cleaner and more beneficial way of doing your code and it's completely separated we've now got a helper class that can you can use anywhere else you can you need test you can do a lot more where this is just you know the best way of doing it and the mean we try to think of what wire of we done all that work just think about apps today and not just on Windows they're on multiple platforms or on Mac Linux they're on like embedded windows they're on androids iOS is you name it there's so many places where your code used and this code can be used in dotnet core which means you can literally compile all of this code with the exception of this tiny UI class into a completely cross-platform codebase using.net core so that means you could literally take this exact project right now and run it on the iOS and all you'd have to do on iOS is to create the UI so just create a basic stack panel that shows and show you what it looks like yeah you can't see but you've seen what that looks like you just have to create the stack panel that shows an image and a an expander and a name and that's it that is all you have to do to make it work on iOS so we'll do more obviously on there view models but now in future we'll start moving all these things like base view models and over helper stuff into like a core library so we don't keep repeating ourselves and then I'll put all this shared code on github so you can download it and a new project products can start making use of these you know things were starting to create now I think in the next video we are going to start moving on to the chat application we may do a few little things in between maybe a few little bits of game logic or whatever takes a fancy but the goal now is to start making the UI for full chat program and then we can now use view models to do that and you know we'll go from that so I hope you enjoyed this [Music] you
Info
Channel: AngelSix
Views: 324,031
Rating: undefined out of 5
Keywords: c#, wpf, mvvm, viewmodel, view model, tutorial, guide, treeview, tree, programming, ui, basics, beginners
Id: U2ZvZwDZmJU
Channel Id: undefined
Length: 72min 54sec (4374 seconds)
Published: Fri Jan 20 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.