MVVM Dialogs: Showing Dialogs in an MVVM Application with a Dialog Service

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
everyone brian lagunas here and today i'm going to answer another tech question if you have a tech question you like to have answered just just ask it below you don't have to subscribe you don't have to like anything just ask your question and if i uh find time or know the answer i'll do a video on it so uh can't wait to see what you ask in the comments below now let's get to today's question today's question comes from lots of people honestly i i forgot it's been so long since i've done a video i've actually forgotten who asked this question but it was a number of people a number of people asked this question and it was all about showing dialogues in an mvvm application now this video is a long time coming this has been at the top of my list i really wanted to get this out to everyone and so basically the main question is well in an mvvm application where you're not supposed to access or use any view objects in a view model how do i show windows and show dialogues and respond to them closing and all that great stuff well i'm going to show you how to do that in this video we're going to start with the basic abstraction of creating a dialog service and then we're going to build on that service to keep adding more and more cool little features so i hope you learned something uh i hope you enjoy this video and uh well let's just go ahead and get right to it okay so the application we're gonna be working with today is a very simple wpf application as you can see our main window has a single button on it and when we click that button it's going to execute a command called show dialog we have our data context set to a main window view model so if we take a look at that view model we'll see that it's a very basic view model that has a seam command called show dialog so when we click that button we're going to invoke the execute show dialog method so now the problem here is well how do we actually show the dialog let's start by creating a dialog to show so i'm going to go ahead and add a new window and we'll just call this uh dialog window right makes sense now we have this dialog window and we want to do something with it so let's go ahead and i don't know i just want to show something so maybe like a text block or something like that we'll throw some text in there let's say uh this is a dialog uh we'll go the uh horizontal alignment center vertical alignment center and we'll set the whoops the font size to something big like 72 something like that okay so this is the dialog this is our dialog here and we want to show this and it's a window right it's a window we need to show a window from a view model but the rule is that you're not allowed to show or access excuse me you're not allowed to uh use or access a ui object in your view model okay so what do we do here how we can't say you know var dialog equals new dialog window i mean we can't do that that's that's not allowed as with anything mvvm right it's it's all about decoupling okay how do we decouple the showing of a dialogue from the view into the view model how do we make that separation but still perform the action well we need some type of abstraction and for me that abstraction is always an interface so i'm going to go ahead and i'm going to create a new class i'm going to call this dialog service that's right we're going to create a service now i always start with an interface but this is just demo code so for this for this demo here i'm gonna kind of put everything in one class but uh ideally this is gonna be separated out where you'll have your interface in one project maybe like a core and then implementation somewhere else right i'm gonna call this i dialog service uh service oh i guess i better put my uh interface on here great and we're gonna have avoid show dialog method right we're gonna show a dialog now our class here is going to implement this uh interface called i dialogue service we'll go ahead and implement it and what i'm going to do is i'm just going to say a var dialog equals new dialog window right and we'll say dialog dot show dialog okay now what i want to do is i want to go into my view model i'm going to have my i dialog service call this dialog service actually i want to underline theirs that's how i do my private variables and we'll say equals a new dialog service now in a production application i don't even do this in a real world application i'm injecting the service this interface into a constructor i never really knew anything up but this is demo code so we'll go with it okay so now i'm going to say dialog service dot show dialog all right so let's run the application and see what happens here's application running i'm going to hit the show dialog button here boop and actually it opened up on this other screen over here so i'll just drag it over but yeah this is a dialog alrighty looks pretty good uh works exactly how we would expect it right we were able to uh to show this dialogue without actually referencing this dialogue in our view model uh i'm actually going to make a quick change just for debugging purposes right i'm going to set the windows startup location to uh like center screen so next time i run this i'm gonna run it and show it it should show center screen and not off on my other screen over here okay so this is this is pretty cool right i mean we were able to take this dialog this window this ui component abstract away and show it but let's be real this isn't really what you're gonna expect you're not gonna say well brian i don't wanna create a dialog window with custom views and all that for every single view i wanna show i would really like to have just this idea of like a shell right this little shell window and i just kind of inject my content into it well because we have this abstraction of our dialog service we can start getting a little creative now we can start kind of building on this uh this abstraction so for example let's say we want to do something like uh provide a name of the component that we want to show or the name of the view we want to like inject uh into the dialog window so what we can do is how about we just add a little overload here we'll say string and we'll call this name and we'll say string we'll call that name now instead of uh for example just showing the dialogue with basic content let's create let's create a new view let's create something like uh let's create a new user control and i'm gonna call this notification uh yeah i'll just call it notification it doesn't matter what we call it okay and in here let's go ahead i'm gonna copy and paste some stuff let's i'm gonna copy this i'm gonna paste it in here instead of this is dialog this is a notification okay so we have some we have some different contacts here uh and actually yeah yeah let's leave it here let's leave it here uh now now we have our notification let's go back to our dialog service and now we wanna what we wanna do is we to say hey when i show this dialogue i want to show the notification right that's what i want to see i don't want to see some standard window that we created i want to see a window with some some injected view into it okay great so how would we do this well we note that a dialog has content right so what we can do is let's go ahead and use the dot create instance and we've got to create a type so before we hop into that type let me just hop up here we'll say var type equals we'll say type get type dollar sign because we're going to throw some stuff now let's see this is called dialogues and mvvm dot and then we need the name all right because we're creating this type i have to have the namespace which is dialogs and mvvm that's where the dialog is located and now that i have that i can go ahead and throw the type inside of here okay now we're going to go ahead and create that content and inject it right we're going to set the content we're using activator.createinstance uh in a real application you might be doing something with con with injection like dependency injection right but we're going to do the cheap way and now let's run the application and let's see what we have so now i'm going to hit the show dialog here's a show dialog and looky there this is a notification well that's pretty cool i was able to inject right inject a different view inside of the window i'm showing so i could technically create another type like an error window and when i call this i could just say you know show error well that's pretty cool uh but we you know we can do more like we can keep building on this abstraction because we built this abstraction between our interface and the implementation now we can we can kind of take this a little further uh so for example what do we need you know what we need to be able to do we need to be able to close the dialog right we need to go to our notification i'm going to change this to a stack panel i'm going to add a button we'll call it close me and let's go ahead and add an event handler to it right and what we want to do here is we want to close the window but because this notification view is within a window what we can do is we can get the parent window by saying hey uh equals this dot parent as window right and you might want to do a null check but i i know it's not the case so i'll just say close uh that that works for me right all right let's go ahead and run the application and see what happens okay so here's the application running i'm gonna click the button and here's our notification close me and it closes well that's pretty cool uh that's really cool actually but let's take this a little further because our view model might need to know uh when this when this closes right we want to know when the dialogue closes from the view model so we can respond to it so let's go back to our service and let's do this let's add an action with some type of uh some type of parameter let's make it a string okay and we're going to call this a callback okay let's go ahead and implement that here action type of string callback and what we want to do now is whenever this closes we're going to notify this callback that the that the window closed and we want to do something with it so uh what we can do here is we need to create uh basically an anonymous delegate an anonymous uh event handler if you will so i'm going to say what should we say i'm going to go event handler close event handler oops equals null i always want to start with null because then we're going to say close event handler right we're gonna say close event handler equals this we're gonna use this anonymous method here uh and we're gonna say callback and then what i actually to do is i want to grab the uh i think it's called dialog result yes and to string it this is the dialog result uh and then what we want to do is to prevent any memory leaks we're going to say dialogue dot closed minus equals close event handler so now you could probably guess what i'm going to do next dialog dot closed plus equals close event handler so what we're doing is we're creating this event that we're handling we're hooking into the closed event whenever it closes we're gonna call the call back and this method here right we're going to call this callback passing in the dialog result as a string and then we're going to unhook the event to clean up any memory so what we want to do before we run this let's go back to our notification here instead of saying window.close why don't we set the dialog result i think it's called right or is it just results forgot what it's called results oh excuse me window dot dialog results equals true sure so now let's go back to our main window view model and as you can see we have this little issue here we have this uh show dialogue it's underlined one because we have to have a call back now uh what this callback gonna look like it's gonna look like results just like this and uh what do we want to do here you know what let's just i'm gonna hit the debug we'll say var test equals result and we'll just hit a little break point because i want to actually see this so let's run the application okay application is running i'm going to hit show dialog here's our dialog close me well look at there our main window view model has now been notified that we are closing the dialogue the dialogue has been closed and i get a result back see this is the true that we passed through so what i'm going to do is i'm going to show the dialogue again but this time i'm going to hit the little x button here so i'm going to hit x what's our result false it's false because we hit the x button so now we know how the dialog was closed was it closed uh by hitting the x button was it closed because i had a cancel button or an ok button like you can control any of the parameters you pass back to your view model to respond to that closing right to that to that dialogue closing okay so you know what i'm really happy about this abstraction that we've built around our dialogues but i think i think we could do some really cool stuff here so let me close this stuff out that i don't really care about don't care about that i don't care about this so let's go back to our show dialogue service okay now another thing that we can do here is what if we wanted to do something more strongly typed uh because right now you know i'm saying show dialogue in this string right this is like string but what if i want to say oh you know show dialogue this type of view model because i'm doing some type of mapping right so let's work on the api okay let's work on the api a little bit so i want to show dialog of like view model something like that right and then we can have our action call back here all right so let's go ahead and implement this and i know that we need to start abstracting away this code because now we have two show dialog methods and i want i don't want to copy a bunch of code right we don't want to copy a bunch of code so let's go ahead i'm going to take this code i'm going to extract a method called show dialogue internal right i'm gonna move this back to the top okay so that's gonna work for now i think that'll work for now we'll we'll we'll improve this as we go okay so we have our show dialog uh what we want to do now is we need to create some type of mapping right because we need about a map the view model that we want to use to the actual dialog type so let's go ahead and create maybe a static yeah let's let's make this a a static dictionary type type i'll just call this mappings right and we'll say it's a new dictionary and then i want to throw i want to throw some like register methods in here really really just one just one so we'll say public void register dialog right and then we're gonna allow them to register the viewmodel against the dialog type right so we can say something like t view and t view model something like this okay now what we can do is we're going to want to check uh you might want to check if the mappings already contain this maybe maybe you care maybe you don't care but in this case we're not going to worry about it in this case i'm just going to say hey mappings.add type of t view model and type of t view okay see where i'm going with this so in a real in a real production application you're probably going to want to do something a little more involved but for our purposes this is going to get the point across just fine oh and i need to make this static almost forgot about that part okay so now what we want to do is we have this mapping so now we can grab that that name or that type out of our show dialog method from the mapping var type equals mappings uh index of type of the viewmodel right and i should actually actually do i should stick with my convention of saying tv model okay so now i'm going to grab the type so this is the view type that we're going to get and this means that i actually want to show i actually want to change this from string to a type i'm going to take that out right okay so we're gonna we're gonna modify that and then i will fix this here because i copied and pasted that out so now i can call it by name but this probably is going to work so well because we're hard-coding that but we'll just fix that for now so we have show internal type now that i have this type i can say show dialog internal type and then our callback again okay so you see what i'm doing here i created this this static dictionary to hold on to our mappings to where we can map our view models against our views okay then what i'm doing is i am creating a register method so i can register those those mappings in my application you know what let's just do that now uh let's just go we can do it anywhere maybe in the main window view model or excuse me the main window in the constructor i can say oh wait what's the name of it it's called the dialog service dot register dialog the view which is the notification and then we need a view model we don't have a view model for this so let's go ahead and do this add a new class we'll call it notification if i can spell nope i can't notification view model okay we'll say this is a public class if we want to uh derives from bindable base okay we can add some properties on here if we want you know no big deal whatever we want to do we can do it whatever and then now we're going to say notification view model now this is okay it's okay to reference a view object outside of a view model that's why we can do that here heck you might want to have a registered place here in your application where you do all your registrations but this is the idea we're going to register this dialog whenever we call notification view model we're going to show off the notification yada yada yada okay so now that we have that here what i want to do is i'm going to update my view model my main window view model and actually i'm going to comment that out and instead of showing the using the text here we're going to use our little override a notification view model right we're going to go ahead and run the app again here's our application running show dialog this is a notification lookie there close me here's a result true so it's the same behavior right it's the same behavior but we were able to remove those magic strings that a lot of people don't like and now we can like navigate or show dialogues based on strongly typed view models now once again you could take this even further because now we can add overloads to actually set the data context you know so if we're showing a show dialog type of t uh you know we can take this type and we can set the the binding context of the view right so the content so for example let me just show a quick example we'll say var content equals activator.createtype and then we'll set that to the content but since we have the view model type up here we could also pass that in if we wanted and we can create an instance of that we can say var v model equals same thing activator create instance right da da da da but in this case it would be the vm type which we haven't passed in yet and then you could say content dot data contact what content as uh what is this framework element add our usings here right we can do that and now we're setting the data context automatically uh now once again we would have to modify this to pass in the vm type so we can say type vm type right we want to pass the vn type here because we actually have it so we'll say type of viewmodel here we'll pass a null because we don't have the type of viewmodel here because we're not doing it and that means what we'll want to do is we will want to add a little bit of code here saying hey if the vm type is not equal null then we're going to run this code right something like that you get the idea you get where i'm going with it so now what happens is when i'm registering this uh where do we do that code behind yeah when we register this notification with the notification view model we're taking advantage of this abstraction that we've created with our service and now we can do more intelligent things like oh i'm just going to go ahead and set the view model i'm going to create the view model because i have it and i'm going to set the data context of that view that we're creating before i set it to like the content here okay so just to review this is what we did it overall we had a command which was in a view model that when we clicked we wanted to show a dialog so we created a dialog service this service exposed a method called show dialog now we were able to take advantage of this abstraction between the interface and the implementation and hide away all the ui stuff that view models aren't allowed to know about and then we implemented our logic you know what we're creating a dialog window not only that we're bringing in dynamic content of the window we're hooking into some events we're creating things we're setting data context and we're just wiring everything up but our view model doesn't care about all that abstraction right we made it so easy that this just works in the view model not only that when you start doing production applications and doing things like dependency injection and you're not newing things up things get really nice really fast really easy to maintain really easy to extend really easy to test but essentially anytime you have a question about how do i do this with a view model it really comes down to creating that level abstraction to where you abstract away the ui implementation concerns from the view model concerns and a big way to do that is with an interface and with a service that implements that interface now in a real application this interface is going to be in another assembly like a core or shared or something that's used throughout your application but the implementation may be in just one location right or in like your ui object i should say your ui project that's where the implementation would exist that's it that's how easy it is to show dialogues in nvvm uh just using a very simple abstraction with an interface alright well i hope you all enjoyed this video and i will see you all next time [Music] you
Info
Channel: Brian Lagunas
Views: 2,132
Rating: undefined out of 5
Keywords: mvvm dialogs, showing mvvm dialogs, showing dialogs in mvvm, mvvm dialog service, wpf mvvm dialog, mvvm dialog example, dialog service mvvm, wpf dialog service, mvvm, Dialogs using mvvm, mvvm wpf, dialog mvvm wpf, mvvm design pattern, mvvm c#, wpf mvvm, interface, dialog, mvvm dialog wpf, wpf dialog mvvm, show dialog wpf, open dialog wpf, open dialog mvvm, show dialog mvvm, dialog service wpf, dialog service c#, dialog service wpf c#, window service wpf
Id: S8hEjLahNtU
Channel Id: undefined
Length: 26min 12sec (1572 seconds)
Published: Mon Nov 22 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.