Switching Views - WPF MVVM NAVIGATION TUTORIAL #1

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
today i want to talk about navigation in a wpf mvvm application so i have covered navigation before on my channel and it is a very popular concept on my channel because as you can imagine most apps need some kind of navigation and in wpf it's not always the most straightforward thing so i want to revisit this concept brush up on a lot of those topics and explore other scenarios because there are quite a few different scenarios for navigation you might have a navbar you might want to navigate in your code after some kind of action such as login so i want to cover as many of those concepts as possible in this series so let's begin by laying down the infrastructure for navigation and setting up a basic navigation scenario just switching between pages but first let me introduce this demo so i have my main window and the data context for my main window is my main view model so if we go to my view models let's look at the main view model my main view model is going to have a current view model and the current view model is going to determine what view we are currently on so for example if we're on the home view model i have over here i want to be on the home view so as you can imagine navigation will just involve changing the value of this current viewmodel property but first we need to configure the mapping from our home view model to our home view because it doesn't do that automatically even though they are both prefixed with him we have to manually do that and we are going to take care of that in the main window so as we recall the data context for our main window is our main view model and of course we can use the main view model to get the current view model for the application so here in the main window we can bind the current viewmodel on our main viewmodel to the content property of a content control so content at binding to the currentviewmodel and of course let's go ahead and set the currentv model so by default we will have the current remodel be the home view model so just instantiate one of those and as you can see we do render the home view model that is indeed the home view model but we don't map it to the home view so to do that we can define some data templates inside of our content control so our content control resources can have data templates inside of them and we want to define a data template for the home view model and we're going to have to import our viewmodels namespace so to do that we can define a namespace up here call it viewmodels and just start typing viewmodels and we should get the namespace in the intellis it's maybe not when we're running let's go ahead and try this again nevermind actually my visual studio is just going to crash real quick all right so back to importing the viewmodel's namespace let's begin typing rv models and there we go navigationmvvm.viewmodels that is indeed the namespace so now for our datatype for the data template we can use our homeview model we want to map the home view model to the home view and of course we're going to have to import our views so there we go we can just do a control dot on there and here we have our name space so now the home view model is mapped to a home view so whenever the current view model is a home view model then we will show the home view there we go that is indeed my home view and before we forget we should go ahead and do the same thing for the account view model so set that as the current view model and now let's copy this data template and make the changes as necessary so the account view model will map to an account view and here is our account view so setting up data templates that is the first step to setting up this infrastructure for navigation but now we actually want to navigate so whenever i click this home button i want to go back to my home view and if we look at the account view model we have the command to navigate home that's what that home button is binded to and somehow we need this navigate home commands however we implement it which we'll do in a little bit but we need that command to tell the main view model to change the value of the current view model and this is an example of view model communication which i have done a video specifically on and i'll have linked below so rather than our navigate home command referencing the main view model and changing this property instead we'll tell some kind of mediator object about the new current view model and then our main viewmodel will grab that new value from the mediator and i like to call these stores because they store application state in this case it's the navigation state of the application and i go over why i call them stores in my viewmodel communication video but for now let's go ahead and create a new folder for stores we're storing the navigation state for the application so this is going to be a class called the navigation store and we'll go ahead and make this public and since we're storing navigation state we're going to store the current view model for the application here rather than in the main view model so we're going to copy this actually and move it into the navigation store and import what we need this is read only right now we only have a getter but we are going to want to make this a setter as well so that we can change the navigation state for the application and actually switch views so rather than our navigate home command telling the main view model about the new current view model it's going to tell the navigation store about the new value for the current view model so let's go ahead and implement this navigate home command so we'll call this the navigate home command make it public and i do have a command base in this project just to scaffold out the basic i command interface so we will extend command base implement the abstract class and all we got to do is override this method so when we execute the navigate home command we're going to set the navigation store current view model to a home view model so that being said we are going to need our navigation store inside of this command so let's create a field for that import the navigation store and generate a constructor and now all we have to do is set the navigation store's current view model to the home view model so now the current view model in our navigation store will be a home view model but that's not going to change anything because our main view model isn't getting the current v model from the navigation store so inside the main view model we're gonna need our navigation store in here as well so we'll create a field for that and we can add that to the constructor and now for this getter we can just get the current view model from the navigation store so just delegate this property to the navigation source current v model property and we no longer need to set the current v model in this constructor and before we forget let's go ahead and set up our navigate home command inside of our account viewmodel so our navigator home command will be a new navigate home command of course import that and that needs our navigation store so we can just get that through the account view model constructor let's generate that constructor parameter and let's just import this namespace so almost ready to test this out let's go ahead and update our app.xaml.cs so our main viewmodel needs the navigation store let's create one of those and just instantiate that and then we can pass that into the main view model now actually if we run this we get nothing on the screen because we haven't set our initial view model on the navigation store so let's go ahead and set that up we will set the current view model at the beginning of the application to the account view model that needs our navigation store as well so that we can use our navigate home command all right here we go so we got our initial view model for the application and now let's go home and nothing happens why does nothing happen am i going crazy let me go to my navigate home command make sure we're actually getting into this command and we do indeed execute this command so the last execution worked as well because the current v model is now the home view model but we're still showing the account view and why is that if we look at our main view model the current viewmodel property on our main v model which is what our content control content has a binding tool points to the navigation store's current view model but whenever this current viewmodel on the navigation store changes we never raise an on property changed for the current viewmodel property on our main viewmodel so the view never re-grabs this value and shows the updated content so what we need to do is raise one property changed for the current view model whenever the navigation store's current view model changes so the best way to implement this is with an event so we'll just have a public event it'll be an action so the event handler for this event will just be a function that returns void and takes no parameters and we'll call this current viewmodel changed whenever we set a new value for the current view model we're going to want to raise this event so let's open up this property and of course we're going to need a backing field now for the current view model so the getter is going to be pretty straightforward just return the current v model field but in the setter not only are we going to set the current view model field to the set value but we're also going to raise this current v model changed event so i like to wrap my event invocations in a method and we'll call this one current viewmodel changed generate that we'll take our current viewmodel changed event and if it does not equal null so it has something subscribed to it then we will invoke it and all the subscribers to the event will be notified and who exactly wants to be notified well that would be the main view model so when we get our navigation store we are going to immediately subscribe to the current view model changed event we'll generate a method to handle that event so one current view model changed and when the current v model changes on our navigation store we want to raise a property change for the current viewmodel property so the view regrabs that value and renders the correct view and to do that we can just call one property changed and the name of the property that changed was the current viewmodel property and only property change that's just implemented on my viewmodel base and all it does is invoke the property changed event that is required for i notified property changed and here we go let's go home there we go perfect and go to our account and we haven't implemented that so let's go into our home view model and we're going to need to implement the navigate account command and i just want that to send me back to the account view so let's go ahead and create that command the navigate account command and this is going to be extremely similar to the navigate home command so actually i'm just going to copy all of this into my navigate account command make sure i fix this name to still be the navigate account command and import the navigation story but instead of going to the home view model we are going to go to the account view model and our account view model needs the navigation store we have that we can pass that in and that back in the home view model we can set up this command to just be our navigate account commands and this needs our navigation story so we can get that through the constructor generate that parameter and since this constructor changed we have to update it in our navigate home command because our home view model now takes the navigation store all right so let's try this again go home go to the account so there we go we are successfully switching between our views if i want the first view to be the home view model just got to change that in my application startup there we go got the home view looking good but of course you may notice that we have these two commands the navigate account command the navigate home command and watch me click between those they're pretty much exactly the same all we do is set the current view model for the application the only difference is the v model that we set so really we should just generalize this command to be one command called something like the navigate command because otherwise we could end up having tons of commands over here just to do this simple navigation to a different view so what i'm going to do is delete one of these commands so we'll delete the navigate home command and rename this to the navigate command and as we recall the only thing that was different between these commands was that we were instantiating different view models so we can actually abstract this to a callback that will give us back the viewmodel that we want and that callback will be a func that returns some kind of generic view model so a tv model and since we're using generic types here this navigate command will be a generic with the type being a tv model and we'll call this callback create viewmodel because that is what it's going to do when we call this funk it will return our viewmodel so let's get this callback into a field and now when we call this function it'll return the tv model and we'll set this tv model as the current viewmodel for the application but we have an issue and that is that the current view model for the application needs to be a viewmodel base so we need to set that constraint on whatever this tv model type is because this type could be anything it could be an integer and of course we can't set the current view model to be an integer so we have to constrain this with a where to ensure that the tv model is a viewmodel base so whatever this tv model type is needs to inherit from viewmodelbase and that is indeed our scenario so for instance on the home view model our viewmodel type is simply the account viewmodel which does inherit from viewmodelbase and all we have to do is pass in a callback function that returns an account viewmodel and takes in no parameters so we will define that here and the account viewmodel that we return will just be a new account viewmodel instantiation which takes a navigation story which we can pass in so we can do the same thing in our account view model change this to the navigate command navigating to the home view model which does indeed inherit from the model base so all is good there and the callback function will simply return a new home view model and will pass in all the parameters that that view model needs so now we've successfully boiled down our navigation to just be one navigate command that we can reuse all throughout our application and same functionality as before go to account go back to home and there we go we are successfully navigating between our views and i strongly believe taking this navigation story approach where this acts as a mediator that facilitates communication between our view models is a very powerful approach and is definitely going to help us as we implement more advanced navigation scenarios it's going to be much easier so stay tuned for that so just a quick rundown we have a current viewmodel property on our main viewmodel and this property determines the view for the application by going through these data templates that map v models to views and then our navigation is all controlled through a navigation store which stores the current view model for the application in a centralized state so other v models or commands can update the current view model for the application and whenever the current v model gets updated we've raised an event that the current view model has changed and our main view model listens for that event we call on property changed for the current v model and then our view updates again navigation crucial for any front-end app so hopefully you all can use this in your own applications if you have any questions criticisms or concerns be sure to leave them below in the comments section other than that leave a like or subscribe for more thank you
Info
Channel: SingletonSean
Views: 26,771
Rating: undefined out of 5
Keywords: wpf, programming, visual, studio, xaml, custom, control, generic, system, line, display, timer, template, binding, behavior, c#, how, to, series, tutorial, easy, time, maintain, package, design, part, event, code, framework, static, state, default, view, style, wrap, panel, stack, scroll, viewer, bar, first, width, usercontrol, command, async, exception, handling, func, action, task, void, model, layout, user, password, box, mvvm, validation, notify, error, icon, class, callback, delegate, relay, clean, simple, switching, views, navigation, nav, modal, viewmodel
Id: N26C_Cq-gAY
Channel Id: undefined
Length: 15min 28sec (928 seconds)
Published: Sat Mar 13 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.