C# WPF UI Tutorials: 12 - MVVM View Model Binding to Animations

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] so in the last video we moved to all of the code into its own core project and we also added dependency injection so we could start doing some IOC code anywhere in the project so right now we have the application that loads you've got a side menu and now we can access the view models from anywhere in the application I think now we're going to go back and clean up a few things get them ready for being final so one of the things we can do is we're going to move the side menu out this salmon you want to collapse out the way in instances like this the sign-in page you shouldn't need this menu will sort out this button being somewhere else I think up here maybe four settings but basically this is when you logged into the application so this shouldn't be here right now so we're going to basically get that out of the way and again as the same when we change pages we have this animation we haven't finished changing pages yet but you see the animation and we also want this to like slide out the way and slide back in and we also need to stay within binding with view models so we want to do binding on this side menu and we also want it to animate so this side menu right now is just a control or custom control and we want to animate it off the screen or on the screen based on a property so we'll start by adding that property to the app view model application view model and we're going to add an extra setting here a boolean of side side menu visible and by default we'll have it as false so true if the side menu should be shown that's our view modeled on now we want to bind to this side menu visible now because within an animation it's not like we're just going to bind to visibility or bind to width and use a value converter we're actually trying to play a storyboard to animate out and animate in we've done that once before in the text style for the spinner so when the login buttons busy spins that was done with a data trigger but that's in sam'l so I'm going to show you a different way of doing that as well as been able to then do more advanced things in code behind so again the only thing you want in code behind in your WPF project is always just pure UI codes as much as possible it shouldn't really have any other code behind in the UI it should all be in your other project should you know your core project or your view models that's where your logic should be but this is purely for UI so what we want there's a new attached property here that we'll use to animate something so we want to first because we're going to have say a default value of false which by default is then it is the default value of boolean in this case if we then make a attach property that starts false so we want to start with this hidden we're not going to get the we're not going to get the property changed event firing so right now we have a value property where if we move this down so it's easier to see we have this metadata on the property for any attached property and we have a property change callback and then on that callback is when we'd then you know animate but the problem is this will get fired if we use a boolean which we will be using and the value is already false so we instead of just having a value changed we need one that happens all the time when the value is set even if it's the same value so then we can override this call and we have coerce value so default value will just set as default of this is called property and then we've still got the property changed and now we also want to add a new coerced value call back and coerce is just usually used to convert a value you know tweak the value hence the would coerce value we're going to just use this as sort of a pass-through that we know that our value is trying to be set so think of this as more you know what value what date it as a value changed it's it's you set a boolean to true and then you set it to true again this property change wouldn't fire whereas because we're using a coerced value it's always called regardless of whether it's changed owner so this works ideal for our animation event because we want it to fire even at the very start when we're first loading up and nothing technically changed because we still need to set the animation to hide the side menu so we created coerce call back for call us on value of gated or on value property updated and it's slightly different than the property changed so we can copy and paste this it's close enough call back when the property has changed even if it is the same value property updated and you still get the dependency object but now you just get an object of the value so we don't actually get you know the value itself and then from MA we want to slide this out the way as the wrong with terraria doesn't it also needs to return the value because the point as it takes on a value and then tweaks it and returns it so now we want to just fire that's will be value won't fire a new event on value updated which will also need to add and value updated here and then we just return the original value because we're not going to change it so now we have these two calls we will have an updated event as well so even when the value is the same be an object be a value updated at the sender and the value says the event value updated and we also have an override abble event method here and there's our call that we can now override as well so that's just added to the base attached property the ability to listen out for your values changing or in this case values being set even when they haven't changed so now we need to create a new touch property let's add here plus I will call it framework elements animation attached properties as a big one name so we're going to work on any framework element which is pretty much any UI element and it's going to be four animations and then also there attached properties so clean up the namespaces in fact that plus doesn't need to exist we're going to now make classes so because this animator is going to have multiple animations we'll make a base class first so that we can use what we need from this so I'll call this animate base property and we'll need to know the parent class in this case because we're going to implement custom attached properties it's going to be in the base attached property like normal of whatever parent we passed in and it's all your going to be a boolean because we're going to just simply animate based on a true or false property all the time for this we need to also tell it the parents are still following within the same expected style just like the base attached property does and here so it's got to follow that same thing so we need to new at the end as well I'm not so k so this is a purely it's almost like a superclass of the base attack proc deals we've really done as kept abstract bubbled or forced it to always be a boolean value but we can still pass in any parent so this is just a base class to run any animation method when a boolean is set to true and a reverse animation and set to false so there will making you one of this way it swipes over to the left when it's false to hide the menu and swipes back to the right to show so that we're going to use this base one afterwards so now we've got the base we're going to override the value updated so whenever the value changes at all and in this we want to first make sure with our framework elements because that's what we're expecting in this is it should be attached to framework elements so we can now do if it's not sender is a framework element will call the variable element so if it isn't a framework element simply return otherwise we've now got a variable called element of type framework element so we know it's been attached to you know a UI element and then from that I guess we want to we still want to make sure the value is changed because if somebody sets the side menu true and then they set it to true again you don't want the side menu to slide in twice so we're on the sender don't get value value property so basically get the current value of you know this because this doesn't pass them the original value this is this is what it's going to be set to afterwards but we need what you currently is so this is like jacking of exchanged so if that equals the same value then you want to return so don't fire if the volume doesn't change and you might be thinking right now well you just said we need to fire whenever it changes even if it's the same value that's true but only in the case when it's the first load so if we set it to false so we attach a property to this here and set it to false by default the only time we wanted to fire regardless is at the very start the first load so we can hide this menu after that if somebody sets it to false again it's already hidden we don't want to reanimate it in so we need this value updated to run so that we always get fired but only for the reason of it being fired when it first loads up that's the only point so as well as this check don't fire the values the same we also need to keep track of whether this is the very first time this animation properties been run which would be basically when it loads up so we need a new for a region here a boolean called first load fire yeah first load and it's true by default flag indicating this as the first time this property has been loaded so now we can say well don't fire with values the same but it's also got to be not the first run so basically because the first time that is run or the values different if you invert that logic then we'll carry on so the first time it runs will always hit here regardless of the value because it's never been run before so that will happen for us automatically also if it's the first run what you'll find is if we attach something to here now attached properties evaluate before the elements even loaded so they get a chance to you know alter the element and do what they need before it loads the problem for us is that we want to animate this out the screen we need to know the width it currently is in order to animate it that far out while at the point when the touch properties are first run the element isn't loaded so therefore the width is nothing it's not being calculated yet so we could force a calculation on the width but instead a simpler way is if it's the first time it's loaded then what we'll do is wait for the element to load and then run the action otherwise any other time after that we know the elements been loaded we're fine we just call whatever action we need to call so first thing I need to do is say if it's the first load so say on first load and we want to basically hook into the elements unloading event and unhook automatically so I want like a single fire so create a single for self on who cabal event for the elements loaded event so basically a fire wants event so a little trick to do that only the rooted event and left which is what the loaded event handler is or unload is from static - nope so technically it's been assigned and then we'll actually make the unloaded something so in this case we'll create the event and then hook into the loaded event of the element so element dot all loaded plus equals unloaded and the reason we set this to null and not straight set it to this and I'll show you why if I just do this is because in order to make something be able to unhook itself like this we can now say right we've unloaded to the element this will get fired now this event here is fired we want to unhook ourselves so you do element loaded - equals unloaded and you want to you know unhook ourselves so basically that's functional only ever run once and you can see the issue use of a non assign local variable so you try to make this valuable and you're defining it here this is the definition of the variable but inside the definition of itself is trying to unhook itself so this confuses Visual Studio and the compiler so simple trick to that assign ignore and then right after assigning to value now inside here we can now technically on hook it because it's happy that it's been assigned even those Nords been assigned so you can unhook it but by the time this ever gets to here we've already assigned it the actual event so this is this whole thing here basically I don't know if I've done any kind of pattern that other people have done I just made this up years ago of a way of doing like a single you know an event that'll fire once and unhook itself so you don't have to worry about it you know beam on hooped afterwards so I don't know whether anybody else has ever done this but this is the way I do it so all this here just creates a single event that is this event here or effectively now whatever's here so this will run if it's the first load it will hook into the element wait for it to load and then run the code and the code once have run is was just call it do action which is basically whatever we want you know this is an abstract class so this is just for an animation when we override this class then this is the function that actually does something so this will be do option or really do animations the better name because that's what we now want to do we want to do an animation it needs the elements giving the value so it knows what it is and that's really it so do desired animation we'll make that a protected virtual void do animation framework elements and the value the animation method is fired and there are changes the element will new value so that's if it's the first load and once we have done the animation we also then need to make sure we're no longer in first load so first load equals false so now we've run once the next time it gets changed for one it'll then never fire again until the value does change because now that's false and then secondly when we get to this if statement this won't fire so anytime it's the second time around simply call the do animation in fact we also need to should we just copied that do the animation and make sure we're no longer in first load in fact saying that now that's a silly thing to do if we've already got to the if statement then we you know we're not in first loads that sir I put must think so there's the base function I mean just common this actually we don't need comment this because the it's an override method which is commented in the base so first load is set so hopefully you understand what's going on now so this will get fired whenever the value set on here the first time an attached property and it'll also get fired whenever the value changes we only want to run when the value changes unless it's the first time and I'm the very first load this will get fired before the elements loaded all the time that's a guaranteed thing so we then wait for the element to be loaded unhook so we only have a fire once and then we basically do whatever we want to do when it's loaded so all this what will help her class does is really this he just waits for the element to load it's the first load and then simply does something when the value changes so all this is doing is performing this unknown action when the value changes from true or false that's it but the difference is if it's the very first time it simply waits for the element to load so that we've got you know we need to use the element size for animation so that's all that's doing so now we've got the base we can go ahead and create the actual animation so let's make an another public class we'll call it animates slide in left or slide slide in from left property and that's going to override the animate base property of itself this animate a framework element it makes a framework element sliding it in from the left on show and flying out to the right out to the left on hide and the only thing we want to do now is override the do animation of you know what we actually want to do on the animation so in this case if the value so if showmenu basically have the values true concept animate in so the animation will need to be created as well and so about storyboard animations page animations we're going to need copy and paste this class we need framework element animations we name the class and in the file rather help us to animate framework elements in specific ways we want slide and fade in from right as fine we also need to add another slide element in from the right the element to animate this is now a framework elements that's just a copy and paste of the page animations we're just now tweaking them for elements which is very similar create the storyboard slide from right element window width is now going to be the elements actual width fading is the same and what's the same that's it that's that's converting from a page animation to an element animation and same for this one an element the elements framework elements window width is actual width and that's it so we've got now a copy of the page animation class just with these two functions well slave slide and fade in from right with the page sliding this way we want to slide and fade in from the left so we need to copy and paste this and we need to tweak it to go the other way so slide them fade in from left slide and fade in from left I don't think exists knows we need to make that now in the storyboard helped us and it was called add slide from left to go move out the way add slide from right so we copy and paste this in the storyboard helpers add the slide from left animation to the storyboard a distance to the left to start from I've actually wrong from the note everything add slide from add slide from right the distance to the right to start from oh yeah that's right so this is the left to start from add slide from left I create a new animation from left right so just invert these in that case that becomes a minus that becomes a plus so you animate from the left then you start at your negative left you know over here and you animate to zero so you slide in so that's it and add slide to left we no need to do add slide to right when we want to slide out so again copy and paste that add the slide to write animation the story with a blah blah blah the distance to the right to start from and so in this case slide to the left the distance to the right to start from that's wrong the distance to the left to end that because we're going to the left so this will be add slide right actually other than we need that desperate is messing so I'll add it anyway add the slide to left animation the distance to the right any confused here I'd slide to left animation I'd like to write animation the distance to the sliding to the right that way oh yeah for when we slide in add slide to right so that's B the distance to the right and right there we go I was confusing so slide to right means you start heading out the way on the left and move in so that looks right add slide to left so going in so add slide to right this is well depends how we I don't then we're going to use this one so to keep it the same we're starting at this place and sliding out is that what we do with everyone oh yeah so we always start at zero and slide it away from zero so add slide to right and slide from left I think the name in slightly off here will sort the naming out another time let's just do the function so add slide to right will simply invert these I should be all the functions we need so back to the the slide and fade in from left that's when the menus coming out we're now slide from left so we come out to the width of the element and yes that should start at - oh yeah so we started from end at zero oh that was right them so we start out the way and we slide into and we start this far out of the way so it's completely out the way we slide into zero and we also fade in so the same as the page animation it's just that we're sliding in from the left hand side so animate in here back at the attached property so if we want to how to make the side menu end then we can now await the element because it's an extension method of elements and we've got the name space right yup so going to do await let's make this an async aliment dot slide and fade in from left and we've got the animations seconds which will default to a third of a second and do that for now otherwise animate out so now we need slide and fade out to left yeah I think that's it slide and fade out to left this also needs a default time three point three seconds slide and fade in slide and fade out slam fade it in so in from right in from left out to left we also want to out to right just a for completeness lies nomination out to the right add slide to right and that's it so go and use that boots they're ready so that's now the attach property so if we attach this property to the side menu now and we give it a value of false the base class should fire this because the value is updated to false from being nothing will pass through all these checks because it's the first load so then we'll get into this first load we'll wait for the element to load and then we'll call this do animation which will then fire this so let's start with that and let's at least see if that works or in fact let's compile first so don't quite a bit of code there let's make sure it compiles so compiles fine so that's at access property to a side menu so to do that we just do a local prolyl on animate slide them from left of a you equals false compile how it's cool and just seeing it actually automatically call it that but this just animate it out let's see if that works again they sit animate out so I'm guessing now if we run this it's going to work and they see so that's led out so we've got a few issues I can see now actually got quite a few issues so issue one notice this bottom corners now got a sharp point I'll have to fix that issue to the grid hasn't shifted over even though it's all the way I think I know why that one is an issue for we actually see this thing slide out when you first open which we don't want to see if this is the initial state to be hidden we don't want to every time somebody opens the app to see the menu slide out so let's fix those issues first I'll start with the easy one so so this is really if it's the first load we don't want to animate so all we need to do to fix that is change the time so the animation of here is point three seconds so let's do first load if it's the first load do it in no seconds otherwise how to make the same answer nice simple fix so basically this is the first initial animation on the you know the very first load basically set to the end point straightaway circuit in no time to animate so it just instantly goes to off the screen so let's run that and we should basically see no there we go so we didn't see that animation at all now let's fix I guess this grid well no let's fix this corner thing first now we've got this shot edge one now let's fix the slide in let's get that sorted so why do we start with that this is in a column of 300 width so chains up to auto to start with and let's set the width of this control to 300 see if that makes a difference nope so that must mean this element is still even though we've moved the margin over oh I know why I just clicked in what we were doing we go into these animations I think it's in the storyboard animation these slide functions so every one of them so we're going to slide from the right we'll go in from we're going from off the screen on the right hand side and sliding from the right to the left and so well really is from right to know yet sliding from the right to where it is but you can see what I did here I basically animated the left margin to the opposite of the right margin so as the element was sliding in from this side it was keeping the the size of the actual element the same so it wouldn't like squash and and move in which is okay but we need to add an override so keep margin we'll call it and we'll set that by default to true for give us a parameter name whether to keep the elements at the same width during animation and this will then be keep margin question mark offsets otherwise you know and then we'll have to sort of copy this for everyone it's got the same issue on everyone that were what's happening is when we're sliding this menu and I don't know how to build them yeah I should do when we slide this menu out this way what we're doing is we're making the left margin negative so this menu slides over but we'll making the right margin positives our slide out this way back up to here so this is basically just a big right hand margin from the animation that's you know been padded out if we remove that this thing should shrink in so we're going to add this property by default so we don't screw up the page animations add this to all of them just going to add the note to all of them first and that's just the fade ins there's only a few so I've added the note now let's add the actual property ah that's the properties I did and now we want to do the same code for the negative mullet the inverse Mulligan so slide from right change the slide from left rather we change the right arm margin slide to left so from where we are out to the left so negative left check probably want to keep the right margin slide to right so from where we are out for left margin and that's it so that's been added to the slide animations we then need to change slide and fade in from left we need to add it to here as well so keep margin by default we'll have true copy that same comment again so keep margin keep merging and we simply pass that into the function there and I was wrong with that Oh dis elevation ratio we need to specify that it's keep margin so same here with the comments once more and that's all those functions so finally now when we call the actual slide and fade them from left in this instance we don't want to keep the margin so keep margin is going to be false so basically animates out the way and the margin simply means that the element will disappear hopefully so let's run this now and we should see that the login page takes up the entire screen yeah there we go let's just temporarily animate that so we can at least see it animate so changes to 0.34 now just for a quick visual so we should see the after the page is going to load in at the same time so yeah you don't really get to see that so let's ignore that for the moment for we can see that that's fits the the margin issue so I think the last issue now is the this cut here so I'm trying to think well this would be [Music] well there's two theory bound that Emily yes that's already bound so that's fine right well let's first get change the login view model I mean let's get something so we can click and and see this thing that I'm eating so at least we've got some repeatable clicks so just use this register async which at the moment when you click that veggies to text at the bottom runs us code so when we click this text here it basically loads the register page let's just hijack that a moment let's just return from there and we want to get the application view model from the dependency injection and change the side menu visible so basically toggle it from being whatever it currently is hide or show so now when we click that link we should see the side menu slide in and out and we actually then we should also see this compress up or not so yes our menu visible oh and on our works we bound her helps if you actually bind the control we just set it to false so this we need to bind the same as we've done here to basically the application view model not current page run side menu visible and that should on out of left the value converter on get rid of that all right so now we know like changes it should animate n which we now missed clicking let that remove that breakpoint there we go so you can see now it animates in and out just noticed yet another issue so if you look right here on the edge down this edge you'll see the other menus animating into the padding so let's slow down that animation so you can see that where is the animation there so let's change that to 20 seconds nice and slow so you can see what I mean so see here now so it's overlapping the edge of the window so let's just fix that I think that's an easy fix I think what we've done is used padding instead of margin in this case so yeah so the main padding of the hole around here so we change this to zero so you can see so this you know the main padding here the reason we added this padding was for adding the drop shadow to the window we've done padding we should just do margin and the difference then is it's not you know just pushing the control then it's telling them that their actual available space is less so I think I should fix that minor issue there there we go so now there's nothing overlapping the edge there that's that bit fixed just change the speed back and so all that's really left is to fix this and what you can see is actually there's the corner and as you're going out I think it's taking the corner where it's almost I think then you can see down here watch a little white things appear down here so that tiny bit of why there it's actually stretched to the background so yes definitely the content is is stretching out it's not clipping inside of its container so I think all's we need to do for that is the thing that contains the when are we can't be bounds the things that contains the page you would go the page contents so this border that holds you know all of the content here I think we just want to add clips to bones so true and that will force any content basically anything we we put in the window then which is this stuff here no it doesn't keep it yeah just so this stuff here the actual content is now going to have to stay clipped inside of the container which is the thing that's got the rounded edge so I think that should fix the clip in hopefully oh yeah so there you go that's gone now so there's no a nice side menu that's actually animating in and animating out based on just a view models property to say when we want to show or hide that menu which is exactly what we want that's sort of the point of view model is we now have an app view model that [Music] defines the state of our application we can set the current page to a page to change the page we can now just set the simple boolean value anywhere in code whether we want the menu to hide or show and now through the binding I'll enter the attack property we now let us a nice animation and you can click it really fast and it doesn't you know nothing breaks it just works as you should so there's a side menu completely sorted now from by default it's out of the way for the sign-in page which is what we want then when we finally go through and you know Sign In which I've just realised we need to press an enter to start that button off as well once we're signed in we can then simply you know bring this menu in and then slide in the the chat page so I'd say that's now done in terms of at least the side menus out the way and slides then again we still going to style this scroll bar obviously to suit and I think next will probably fix this login page finish the animation because right now when you animate between pages so if I go to the login view model comment this out a moment so we can see the register page when we animates the register page firstly the sign-in page simply disappears then the register page slides in we want the first page to slide out while this is sliding in so we need to fix that we also have this navigation bar at the top which doesn't confine to our view model and it's also in the way of our you know expandable drag here it's too close to the edge to to drag so it's our application view model still thinks we're on the login page and we could be on either so I think all will do for now is remove this navigation property and remove the bar and we obviously we handle navigation then however we want an our own application so I think we'll probably fix that in the next video so that the sign-in page register page and the side menu are fully done and then we can add some dummy code that just simply signs in well maybe do a pop-up dialog that can say you know incorrect password if we enter one and then we'll make a default dummy password in code so at least we can get to the sign-in part click login then the side menu can slide out the Chapman you can load in you know get the thing actually functioning fully so I think that's it for that video I think it's been long enough and hopefully we understood all that again it's just another way of using the attached properties to then run some custom code of you well in this case starting animation what we could have done anything with that but that's one way of now adding an animation to any framework elements so you should now be able to attach this not this attached property to any framework element at all and set it to true or false have it animating in and out based on whatever value you decide to bind to so we could have touched this to something else anywhere in the application as well doesn't even have to be here so let's go to say where's the login page pages login page let's attach it to this button no idea of us our work simply attach it to the button exactly how this and run and we should see that this login button isn't there when we open there we go on we animate in login button animates n as well and animates out so you can literally attach this to now any literally any element you wants you can interact you to be easy connected to this you could detach it to any UI element at all in the application and get this effect you know the thing we've made this animation so hopefully that's made you realize how useful sort of that attack property is so we can say attach it to this password box let's see the password box works as well what you should do because we're just simply messing with the margins click the Run button and there you go see it's fading then you can see that it's a it's not clipped within the bounds here so you see the password box sliding out but again to fix that we should have to just I think I need some stackpanel click the down screw I think that'd be enough and there you go so again just an attached property that now works with our custom animation so just check up on done all the temporary code I'll leave the better code in that animates on this button just so you can play with it yourself and again I'll put the link to the source code in the video anything you don't understand in video is if things are confusing to you again I just do these the way I you know naturally come up with them at the time if you don't understand anything feel free to just comment and I'll definitely get back to you I can even do follow-up videos for you no tricky problems or go in a bit more deeper into explanation so don't feel like you don't understand it you just you've got nowhere to go simply comment and I'll get back to you and you know help you understand it [Music]
Info
Channel: AngelSix
Views: 35,058
Rating: undefined out of 5
Keywords: wpf, data binding, mvvm, view model, storyboard, animation, tutorial, example
Id: ofsdVKrMg8I
Channel Id: undefined
Length: 52min 2sec (3122 seconds)
Published: Fri Apr 14 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.