BrandGhost

STOP Modifying WPF Controls Directly! - View Model Refactoring For MVVM

Rule number 1 about WPF club: We don't talk about WPF club. Wait! That's not right -- Rule number 1 is about directly manipulating our views! In WPF, the predominant way of designing user interfaces is leveraging MVVM. We use binding to get our controls (the views) hooked up to the state of the view models. Through data-binding, when our view models update, the views are triggered to get updates for the new state! This works the other way too, of course. In this video tutorial, we'll refactor a splash screen with a progress bar to support a view model. We'll avoid updating the controls on the view directly and leverage data-binding!
View Transcript
if we're building mvvm applications in WPF then we know that we can't get mvvm without view models hi my name is Nick CTO and I'm a principal software engineering manager at Microsoft in one of my previous videos which I'll link up here so you can go check that out first we were making a splash screen and on that splash screen we were supporting progress reporting in that video though I was illustrating how we can get progress reporting working but we kind of took a shortcut and we put a lot of that code in the code behind of the splash screen itself now in this video I want to transform that code so we'll do a bit of refactoring and we're going to convert that over to being a view model so this will be much closer to mvvm and that way our logic is not directly interacting with the UI controls because that's a big no no in WPF if you're trying to follow all the best practices so if that sounds interesting remember to subscribe to the channel and check out that pin comment for my courses on D train with that said let's go check out our splash screen and start refactoring so in the previous video this is the very beautiful splash screen that we had I won't spend much time looking at this so our eyes won't burn but what we were looking at in the code behind here was this report method and it took in a progress so the splash screen interface itself is an i progress and that interface essentially is looking just like this single method here and we're able to have a typ parameter which is what we Define so the the progress object that we want to have now we were required to have this dispatcher invoke because we were doing this from a background thread and then trying to set the properties on the controls directly and this is a bit of a violation of mvvm because we're not really working with view models the reporting was actually happening from the presenter that we made it and directly modifying the control or the window in this case but we can do better than that we can use a view model and set up binding such that we can have those properties directly update and interact in our user interface without us having to go touch the user interface directly so let's go check out how we can set up a view model for that what I wanted to do is think about these two things that we're setting here so we have the progress bar that has a value and then we had this XT block which is the the message that we want to have those are two fields that come off of this progress info that we pass in so what I went ahead and did was made a splash view model it has I notifi property changed on it so we'll explain that in just a moment it has I progress on it which is what we were using up here right so it's going to be this method signature we'll see that coming up in just a second but then what I wanted to do is with I notify property changed we get this event here which is property change big surprise and then we have to have two properties that map with these fields up here that support this property change type of interaction so we essentially only notify the property change happening when the value is different so that's down here and basically copilot's really good at this point now it just knows how to implement it so if I say I you have to type anything it just knows that we need it so that came right off of co-pilot caller member name if you see up here on property change caller member name just allows the compiler to infer the calling location so we don't have to go do something like this and then say progress value we don't have to do this because caller member name takes care of that for us but essentially I set up these two properties that support notifi property changed and that means that we're able to bind to them so we'll look at that in a moment and then I put this report method in here and that's because I progress splash screen progress here on this view model means that we need to have this implemented so we get this method signature and all that I'm doing is going to set the text and set the value for Progress that's it right it's really just this code up here but then moved into here before we move on this is just a quick reminder that I do have a course on C refactoring available on dome train refactoring is one of the most critical skills that you can learn as a software engineer and this helps you continue to build upon applications that already exist making sure that they can scale and have extensibility I walk you through a bunch of various techniques and give you some examples that we walk through together to see how we can apply these techniques to refactor the code check out the pin comment and the links in the description to get this course now back to the video at this point we've created this view model which is cool it's pretty simple we've just copied basically the exact report method that we needed and then from there we updating these properties but now we have to go use it and now we have to go bind to it as well so we're not just done there so I'm going to start showing you how I started to refactor some of the code to make this work so this is net new code this view model we have to go use it so scrolling back up if I take out this Constructor on our Splash Window if I bring in this other one that I had this is the Paradigm that I like to use so I do use a lot of dependency injection even though WPF isn't super friendly with it it kind of breaks of the uh design features there's kind of hacks around this but I use dependency injection an awful lot so I'm injecting the view model and then from there I'm setting that on the data context as the very first thing even before initialize component and that way in a lot of the controls that I create they have a view model that exists for the exact lifetime of the control itself so the Splash Window will get this view model I'm going to take this part out cuz we don't need this reporting anymore that means that we're going to have a problem with this interface up here it's going to say hey like look we can't do that we have to do better than that and that's because we don't want I progress on the interface for the view Itself by the way you don't have to have an interface for your views again this is coming from a previous video I'm just showing you how I'm cleaning up some of the code to go make that better right so jumping back to here we now have a window that will take in this view model that we've created a very simple one right but it's going to have these properties that we can buy into and it still has the this reporting method that means that someone on the outside is able to have a reference to this view model and say I would like to report progress so view model here's the progress that view model goes thank you very much I'm going to go update my two properties so these two right here I'll go update those and then we have a view that's also listening to this on the property changed event and that's done through binding with those things put together that means that our splash screen presenter I'm talking with my hands here so my splash screen presenter is able to have a reference to this view model and say report progress from there report progress does the internal update and then the view is watching that and then is able to get that update Through The Binding if we put all that together it should work we haven't updated to call the view model and we still haven't done the binding so if we go over to the splash presenter what I want to do is clean up some of this code and if we see in this call back that we had to have the background work get executed we were giving it a progress reporter but the problem is the Splash Window is no longer the progress reporter so let's get rid of that and I'm going to bring in this other code and this is going to look a little bit nasty but this is just because of how we've designed some of the other pieces in here in this presenter which I can clean up but this part as you'll notice this looks terrible it looks terrible because we're asking this window so this is already a bit of a smell in here we have access to the window directly then we're asking for the data context this is one of the things that I really don't like about WPF is that this data context is sort of visible as an object to everyone now we happen to know that it's a splash view model so one thing that we could do to make this slightly better if you bear with me for just a moment because I really don't like that casting even though I set this up before I started recording I'm like no I'm not happy with that so let's go ahead and this is a pattern that I like to do when I'm working with presenters so I like to explicitly put in if I have a splash view model like this um I actually would like to do give me one moment here let's change this around so I'd like to have something like this and then I can do I might even put I don't use this syntax a lot but sometimes to make this a little bit more readable just because the capital letter here in the lowercase one this might be kind of nice I like to expose out the view model like this a strongly typed view model because we're already exposing the context it's the it's literally the same information but it personally kind of bothers me that we just have this object type so if we go back to here instead of doing this now I can ask for the view model and then we know if I hover over this with my cursor we see Splash view model as the type that's exactly what we want to see here so again now that we have something that has progress reporting on it we can go ahead and pass that into here and this will now compile so all that this interface wanted this do heavy work async callback needed a progress reporter that took in splash screen progress and we're now providing that because our view model does that now we have the input going in to handle this and that means that the caller inside of the do heavy work async call back can now report progress that's great but we're not doing anything with that yet so if we were to go run this it would be completely busted the progress wouldn't update and we'd be kind of upset so what I'm going to do is now go to The Binding part which we have to go create so if I go back to this very beautiful magenta splash screen I'm going to take out this code here and I just have a copy of it below all that I'm doing is updating it with the bindings so I'll walk you through that you can see that on the text block I'm just binding to progress text and that's because our view model has that property and the progress bar itself has progress value I'm binding to both of these and that's sort of the missing link on the other end of this whole thing at this point what we've been able to do is take our Splash presenter it can properly take something that has I progress reporter which is going to be the view model it gives that to the thing doing the background work and just to show you where that is in my example application it's actually right here so let me get rid of that code and you can see that it takes in this progress reporter and that way it can report on the progress right here it's doing that work already great then our view model like I showed you earlier that's going to propagate those changes through and raise an event every time they change and the final part we saw is that we have these bindings in place so if we go run this we should see a very beautiful magenta splash screen and our progress should be reporting just as we expected and one last thing to show you just to remind you I did delete the progress reporting directly off of the Splash Window so there's no other code lurking that would be doing this just our happy path and there we go our very beautiful magenta splash screen and as you saw we ended up having all of that update for Progress so if I go ahead and run it one more time to show you you can see that that progress is upda right the fact that we saw those controls update as it was going tells us that The Binding is working now we've refactor this a little bit further we've put a view model in place which is great we could see how the binding works but there's still a couple of code smells with this Splash presenter and I like walking through this whole example because we can see we can start with some working code and we can start refactoring it to have the patterns that we want to propagate further so the thing that I don't like about this presenter still is that it has reference to this whole Splash Window ideally I would just like to have it work with the view model so instead of Splash Window I really just want to have Splash view model but where does that start to fall apart if we have a quick scan closing so we don't have an event handler on there that might be something we could do easily on The View model but the other thing is that we have this show and close so it seems to me like if we want to start replacing this whole view control in this presenter and just work with the view model we probably have to come up with two workarounds for being able to show the window and close it so if you're interested in seeing that you can check out this video next thanks and I'll see you next time

Frequently Asked Questions

What is the main purpose of refactoring the code in this video?

The main purpose of refactoring the code in this video is to adhere to the MVVM (Model-View-ViewModel) pattern by moving logic out of the code-behind of the splash screen and into a dedicated view model. This helps to avoid direct interaction with UI controls, which is a violation of MVVM best practices.

How does the view model communicate updates to the UI?

The view model communicates updates to the UI through data binding. By implementing the INotifyPropertyChanged interface, the view model can notify the UI when properties change, allowing the UI to automatically reflect those changes without directly modifying the controls.

What are some challenges mentioned regarding dependency injection in WPF?

One of the challenges mentioned regarding dependency injection in WPF is that it can break the design features of WPF, making it less friendly for dependency injection. However, I still prefer to use it extensively, even if it requires some workarounds to integrate it effectively within the WPF framework.

These FAQs were generated by AI from the video transcript.
An error has occurred. This application may no longer respond until reloaded. Reload