Handling Exceptions and Messages - FULL STACK WPF (.NET CORE) MVVM #21

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hey everyone singleton sean here and today in simple trader i want to clean up the way that we report error messages and status messages so as you can see right now all that we do is just pop up these message boxes for success and for errors throughout our application and in my opinion this isn't really the best way to report messages to the user like yeah it works but the pop-up it's kind of dirty it's not the most like pleasant thing to do what i would really want to do is integrate these messages with the ui so for example come into our by view right here i really want to have a text block right here that shows the error message so let's say this would have text that would bind to an error message and of course this is an error so we're going to set the foreground as dark red and we'll just leave that for now but we're going to have to play around with this a little bit more but this is really what i want i want to actually display the error message so of course we set up this binding to this error message and we're going to have to get that from our view model so if we go to our view model the by view model what i'm going to do is put a property down here for the error message so it's just going to be a string we'll call it error message and there we go we can now set this error message from outside the view model so if we go back to our buy stock command we could catch an exception for an error and we could take our by view model and set the error message to basically anything we want in this case we'll just set it to the exception message but we'll clean that up a little bit and now we're not popping this message box so that's the goal that's what i want to do throughout the application so let's test this out and while i'm here i actually want to move this to its own row so let's go ahead and add that this will be row two now and let's type in a stock and let's try and get an exception here and see that error message so let's buy 500 shares we should get insufficient funds and there we go there is our text in this text block with our error so of course this isn't very pretty we're going to clean this up because we want an actual exception we don't want this the user doesn't want to know this they want to know the specific reason that there was a failure but anyways let's clean up this ui a little bit so first off we need to horizontally align this so it's centered and let's give it some margin too we'll give it 10 on the top and another issue we have is that i want this text block to only be visible if there actually is an error message so what i want to do is bind the visibility so we have some options here but we're going to calculate this visibility from a property on our view model so let's go back to our view model let's actually close this out and we're going to have a property going to be a boolean and it's going to tell us if the view model actually has an error message and if this is true then we're actually going to share this text block if it's false we're going to hide it and it's just going to be a calculated property and it's going to use this error message and it's going to check if the error message is null or empty and if it is not null or empty then that means we do have an error message so now we have this property but one more thing before we move on here we need to actually raise one property changed for this has error message property whenever our error message changes because this property depends on our error message so we need to let our ui know that this has a new value when we get a new error message so now back in our by view we need to set up this binding we're going to bind to has error message but we do have a problem here and that is has error message is a boolean true or false but visibility that could be either collapsed hidden or visible so we need to use a converter here now luckily with wpf there is a built-in converter for converting a boolean to a visibility so let's go ahead and use that boolean to visibility converter we'll give it a key of just boolean the visibility converter and then we can use that down here static resource reference and then if has error message is true this will be visible if it's false this will actually collapse so it's not even going to take up any room in our ui so let me go ahead and format this i've been using this format xaml cleans things up very nicely now back in our buy stock command we also have a status message that we have to account for so that means what i want to do is i want to have buy viewmodel and i want to be able to set a status message to say success like that there's no message box so you might be thinking all right perfect we're just going to copy all of this but i actually don't want to copy this what i'm going to do instead is create a new view model and this is going to be called a message view model and now that i have this message view model let's actually set this up just going to be a regular view model base we can move these properties into this message view model and let's actually give these a more generic name so not error message just regular message clean that up for the field as well and then instead of has error message just has message because we're going to be using this view model for status messages and error messages so now back in here let's use that view model so we're going to have a property for a message view model and we'll call this the error message view model and we'll just instantiate it in our constructor there we go and now same thing but we're going to have a status message view model so let's instantiate one of those as well and there we go that's great now back in our buy view we need to update this because we don't have these bindings anymore this is message and has message but these properties aren't on the buy view model they're on the error message view model so we need to set the data context of this text block to an error message view model and that's going to point to this property right here and then all of these bindings are going to be resolved from the actual message view model so that's great let's format this and now i'm going to copy this into another one for the status message view model like that and this one's going to have dark green instead for the text because it's like a happy message and let's put this in its own row you could keep these in the same row but i do fear there is a possibility i guess you could have a status message and an error message so we're going to split them up let's create a new verb for that and there we go that should be everything we need now there is an issue back in our buy stock command we can't just set the status message or set the error message because now we only expose the error message view model and we would have to go through that to set the error message or just set the message in this case but i don't want to do that i don't really want this command to have to like nest through all these properties i just want to actually expose the error message and be able to set it like this so what i'm going to do right here is i'm going to expose a property for error message and it's actually going to be a set only property and we're going to set the error message via model error message or just message to the value that gets passed into the setter so now back on our buy stock command as you can see we can now just call by viewmodel.errormessage and set it to whatever we want now that's great let's go ahead and do the same thing for our status message and we're going to use the status message view model this time and now you can actually close out of this we're done here we can go back to our buy stock command and there we go we're setting the status message now let's clean up these messages a little bit so instead of actually using the exception message all i really want to say is transaction failed so just a basic message and then for the status message what i'm going to do is actually before we get into this i'm going to move these variables to the buy be model symbol and the shares to buy i'm going to move those into local variables right here so symbol and the reason i'm moving these in the variables is because i want to reuse them in my status message so i'm just kind of cleaning it up a little bit so it's easier to read and then we're going to have an int for the shares and now that i have these in variables we can update the status message so i'm going to use string interpolation so i can just use these variables in the string so we're going to say successfully purchased and then use the variable shares so successfully purchase some number of shares of a symbol and there we go there is our messages now that's great but we could do better for this error message because this by stock method it could throw an insufficient funds exception so we could catch this specific exception and then tell our user hey you don't have enough money now what else could it throw this get price that could throw an invalid symbol exception so really we should document all these exceptions and then we would be able to see those exceptions that this by stock method could throw right here and then specifically catch them and give better error messages so let's go ahead and do that and for the documentation we're actually going to document on the interfaces because we use those interfaces if we put the documentation on like these specific implementations we're not going to be able to see them on the interface if we use those so we're going to put those on the interface so let's do some xml documentation but what's really important is what we do next so we're going to document the exceptions that this could throw so we could throw an invalid symbol exception and to get some intellisense on this we can actually use simple trader domain exceptions like that and there we go now we actually see the exception and this gets thrown if the symbol does not exist now back on our stock price service we could also get some generic kind of http client exceptions and we don't throw this specifically we don't really know what those are but we can just say those are just regular exceptions so we can document this will just throw a basic any exception if getting the symbol fails and there we go so now we have that document it's now back on our buy stock service we see all these exceptions so now we know that this buy stock method it could throw an insufficient phones exception or it could throw any of these exceptions as well plus since we're doing some entity framework stuff it could throw exceptions there but we're just going to handle those as regular exceptions as well so they'll just go into this exception category so now we're going to document these for the buy stock service let's get these exceptions in here so we get in let me actually import that namespace so we get some intellisense right here and this could throw an insufficient funds exception and then this could throw an invalid symbol exception and then just a regular exception and that'll be thrown if the transaction fails and there we go so we got those documented let's x out of all that and go back to our buy stock command so now if we hover over this we see all the exceptions that we can handle so now let's catch those so we're going to catch an insufficient funds exception let's import that i guess i spelled it wrong there we go and if we get that let's set the error message to account has insufficient funds and then it's also a good tip when you give error messages to tell the user like what they can do to fix it so we're going to say here please transfer more money into your account and we don't actually have that in the application so this might not be the best suggestion on how to fix this but we'll eventually add that and the other exception we need to catch is an invalid symbol exception and for that we're just going to say symbol does not exist all right there we go so i really like this approach to handling error messages by the way i think it flows really nice just having it down here in these catch blocks and this command looks really clean now one thing i do suggest doing is clearing the status message and error message before you execute any of this because say that this was all successful you're going to have a stale error message in here if you had one before so it's good to clear these before doing another operation all right so let's put in another gigantic number here and attempt to buy and there we go we get our error message up here so that looks really nice and let's actually buy one and there we go successfully purchased so that looks very nice i'm pretty happy with these messages much better than the message boxes in my opinion so let's go ahead and add this to other commands so another command we have is the search symbol command and this uses the buy view model too so we really don't have to update much here all we need to do is handle these exceptions so we already have these documented as well so for a generic exception we can just set the viewmodel error message to failed to get symbol information and if it was successful we're not going to say anything but we have to catch this invalid symbol exception as well so let's go ahead and do that invalid symbol exception my spacing's all messed up here and we're going to set the error message to symbol does not exist alright so we're just going to put in a random symbol symbol does not exist perfect let's go to our login command okay so this is going to need some work and the issue we have here is that this login method if we go to our authenticator it doesn't actually throw exceptions just gives us back this true false flag so we can't handle exceptions all we could really do here in this login command is either set an error message to login failed or login successful and that might be good for you but i actually want to give more specific details so what i'm going to do is i'm going to change this up and i'm going to have this actually throw exceptions instead so we can get rid of all of this and it's actually going to throw the exception so we're not handling them here and we need to update our interface as well and while we're here we should document the exceptions that this could throw now what could these throw well our authenticator using authentication service and let's see what that could throw and that could throw a user not found exception an invalid password exception and then of course we're using our repository so that could throw some kind of like any framework exception which we'll just say is a generic exception let's go ahead and document those on our authentication service so user not found exception and let's import that exceptions namespace so we can get some highlighting on these so there we go user not found exception invalid password exception obviously thrown of the password is invalid and then just a regular exception is going to be thrown if the login fails and there we go let's actually copy these exceptions because theirs are going to be used on this authenticator so same exceptions let's import that exceptions namespace there we go we get the highlighting and that should be all the exceptions that could be thrown so now back in our login command we need to switch this up so this doesn't return a boolean anymore don't have that success flag and we're just going to wrap this in our good old try catch so here we go so it's going to try and log in if the login was successful then it's not going to throw exceptions and then we can re-navigate but otherwise let's handle these exceptions so look at this login let's get that user not found exception in here and now we can set the login view model error message which we haven't set up yet so let's go into our login view model and let's get an error message review model in here i'm actually just going to copy it from the buy view model and we're going to get this setter as well so we can just set the error message so let's go ahead and set that need to make sure we instantiate that in the constructor there we go and then we also need that on the view too so let's go into the login view and i think i'm going to put this all the way at the bottom and i'm actually just going to copy this from the buy view as well so right here and that's another thing we're reusing this ui this could easily be converted into some kind of component so we're not reusing all of this xaml but i don't know i don't really think it's that much to reuse i mean you could have a style too but i think i'm just going to roll with what we have right now but anyways it's going to go in grid row 3 and then we need to add that row and this actually has a column on it we don't need that this whole grid doesn't have columns so that's okay and what else do we need to do here we need to import this converter so let's get that up here and let's just copy that from the by view there we go perfect that should work great so let's x out of that and now we can handle these exceptions so for a user not found we're going to set the error message to username does not exist and then let's catch what else do we need to catch the invalid password exception and we'll set the error message to incorrect password that's another thing with these exceptions and handling these you might not want to give the user this much information about whether or not the username or password was incorrect or not you might just want to tell them login failed and if that's the case you could just handle these exceptions however you feel but in this case i feel comfortable giving this information and then last but not least let's handle that exception and for this we'll just say the login failed all right so i'm going to have an invalid username let's login and username does not exist so now let's do a correct username an incorrect password incorrect password so the last thing i want to do is actually bring in async commands so as you can see we're doing all these it's async void and we have all this boilerplate for our commands as well so what i'm going to do is bring in an async command implementation and i went over how to set this up in a video so i suggest watching that if you're unfamiliar with async command but i'm just going to copy that into this project there we go and of course source control always in the description so you can grab this if you don't feel like writing it out or watching the video on how to set this up but anyways we take care of this execute and then we just override this execute async in our async commands so now back in our other commands we can just inherit from async command base and then get rid of all this i should actually make these read-only let's go ahead and do that real quick and then we don't need can execute as well and this will now be an async task execute async that's going to override the abstract execute async and there we go so we get rid of some boilerplate in these commands let's go ahead and do that for all of these get rid of all that override async task execute async and of course let's bring in that base class and same thing for the buy stock command get rid of that get rid of that task execute a sync import task and override anyways i want to show off why this async command is pretty useful to use so i'm going to search for a symbol here and i click search and it's searching and as you can see when i click that my cursor changes and that's because it actually disables the button so i can't just spam it because we use this is executing flag and then can execute is only true if the command is not executing so you can't just spam the button but one thing i want to do is actually like show that this button is disabled so one thing we can do real quick is go into our styles find our button style down here let's copy a trigger and we're going to have a trigger for is enabled and if it is enabled as false we're going to set the opacity to 0.5 and i'll check this out when i search as you can see it grays out the button so you can clearly see that it's not enabled so anyways that's where we're going to wrap things up we went over how to display error messages and handle exceptions in mbvm commands and then we also brought in this async command as well so our command implementations are looking very clean we simply execute what we need to do and then handle our errors and pass them to the view model and real quick i also said we should clear error messages let's do that right there okay perfect anyways thank you guys for watching if you have any questions criticisms or concerns be sure to leave them below in the comments section but other than that leave a like or subscribe for more thank you
Info
Channel: SingletonSean
Views: 2,524
Rating: undefined out of 5
Keywords: wpf, mvvm, easy, hard, difficult, switch, views, microsoft, visual, studio, binding, viewmodel, property, class, interface, user, control, window, learn, how to, architecture, pattern, new, switching, content, main, programming, tutorial, full, stack, entity, model, access, object, .net, c#, service, layer, project, stock, trade, price, clean, element, data, account, form, image, route, router, manage, store, list, grid, column, header, style, custom, container, margin, items, source, error, exception, handling, message, status, throw, catch, try, navigation
Id: KzHAk7_2h4U
Channel Id: undefined
Length: 23min 32sec (1412 seconds)
Published: Sun Aug 09 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.