Hamburger Menu/Navigation Drawer - WPF UI COMPONENT WORKSHOP

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
i've gotten a lot of requests recently to demonstrate how to create a hamburger menu also known as a navigation drawer for a wpf application so in this ui component workshop we're going to be creating a custom hamburger menu and we're also going to show off how to animate the opening and closing of that menu as well so let me start off by showing off the application i prepared for this demo so we just have a single page and when i click this little hamburger icon what i wanted to do is slide a menu out from the left and that would just have a bunch of options for me to click and this actually based off of the angular docs let me bring that up just to give an example so right here got the same little hamburger icon and just click it to open and close the menu so i want something similar to this i'm even going to be using the same exact colors so let's start off the same way we start off most of these ui workshops by creating a new project to hold our control and that's just in case i ever want to publish these as a nougat package but this is going to be a wpf custom control library and this is going to be called the hamburger menu control i apologize if you refer to these as navigation drawers but i'm just so used to calling them hamburger menus so we're going to roll with that and let's delete this gigantic comment instead of calling this custom control 1 we're going to call it a hamburger menu and this is going to be our control and this control has a default style defined in the themes generic.xaml the location of this file does matter and right now we're still using custom control 1 but it has to be hamburger menu and this default style is going to define the template which is basically how our hamburger menu is going to look but before we get into this custom control template let's first head back into our hamburger menu and think about what kind of properties the hamburger menu is going to have well our hamburger menu can be opened or closed so we're going to have a dependency property for is open which is going to be a boolean the owner class is the hamburger menu and by default we'll go with false that's tough maybe it should be true but we're going to leave is open as false by default so we'll have a hamburger menu that can open and close but what are we going to have inside the hamburger menu we're going to have some content so let's set up another property for content and this can actually just be an object so it can be anything passed as the content and our class is the hamburger menu and by default this can just be null so that's really all the properties i can think of at the moment so let's head into our generic.xml and set up this control template so we're just going to open up this border and have a content control and the content for this content control is going to template bind to our content on our hamburger menu so that's just this dependency property right here and all that means is whatever content we pass into our hamburger menu is going to be displayed inside of our control template which is what we want so that takes care of the content but what about whether or not the hamburger menu is open or not well what we can do is set up a binding to visibility a template binding that is to is open but is open is a true false boolean and we need to convert this to a visibility and we can just use the built-in boolean to visibility converter so we can put that in our control template resources a boolean to visibility converter and now convert this boolean of is open to either visible or collapsed so let's just give this a key boolean divisibility converter and set that as the converter for our controls visibility so pass in the key as a static resource and that should be everything we need to toggle whether or not the hamburger menu is visible or not so i think we're ready to test this out we haven't set up any animation yet we're going to cover that in just a second but let's head into our window so this is what's currently being displayed in my application here's the little hamburger icon that we click to toggle whether or not we want the hamburger menu to display or not so we're gonna have to bind to this and here's our applications title so this is all part of the header and then we have the page underneath that and to the left of our page we want our hamburger menu so we will reference that hamburger menu and before we can do that we're gonna have to reference our hamburger menu control project so let's go ahead and check that and now we should be able to do a ctrl dot and add the namespace that has that control and we just call this custom and this will go in grid column 0 and as i mentioned i want to bind our is open property on the hamburger menu to whether or not the hamburger icon has been clicked or not so our hamburger icon is just a checkbox so we can bind to whether or not that checkbox is checked or not so we're going to bind to is checked and i gave that checkbox a name so we can reference that the cb toggle menu and then we're also going to need some content on our hamburger menu so that is the custom content dependency property that we created and for now we'll just throw in a text block and just say hello world why not so right now we're closed let's click the hamburger icon and there we go so we did have our menu slide out but it doesn't really feel like a menu we need some kind of visual distinction here so let's give it a background so the background i'm actually going to grab this off of the angular website so let's just try and match angular as much as possible so this background on this menu is f2 f2 f2 hex so let's set that all right i kind of see it we should also give this some padding so we'll just throw like 20 in here that looks better increase that font size looks like we also have a border over here so let's try and grab that color so it looks like that's db in hex so that's gonna be our border brush and then our border thickness will be just one pixel to the right so we're gonna put one for this third value and this is looking pretty good i think the last thing we want to do is make this say something like introduction instead of hello world and there we go i'm feeling pretty good about that so now we're ready for the fun part let's go ahead and make the opening and closing of the hamburger menu animated so for this we're not going to be able to just bind to is open for the visibility because all visibility does is either show or hide the hamburger menu and instead we want the opening and closing to be animated by animating the width from 0 to whatever size for opening and then whatever size to zero for closing so we're not going to have this template binding and we're going to set up an animation on the width so in other works such as the hold submit button control let's actually bring that up i did all the animations in storyboards and this is a pretty typical way to do animations in wpf but we ran into tons of issues with having to set up bindings inside of our animations and we kind of had to do some hacky stuff and as a result it's not really the prettiest solution but it does indeed get the job done but i still don't like it so for the hamburger menu we're actually going to be doing the animations inside of our code for our control and it's going to be so much easier and honestly we kind of have to do it inside the code based on what we're going to do so back to implementing this what are we animating we're animating the width and that animation is going to occur whenever we change whether or not the hamburger menu is opened or closed so that being said we're going to set up a property changed callback on this is open dependency property so we can generate one of those so we'll call this one is open property changed generate that we'll move that down here and now for this callback we're first going to check if this dependency object is indeed a hamburger menu which it should be but we'll do a quick little check so if it is a hamburger menu throw that into a variable and then with that hamburger menu we'll call a method we'll call this one uh we'll just call it on as open property changed again why not keep it simple and then we'll generate that so this is open property changed is actually an instance method so we can access all kinds of things like the width of the control whether or not it is open so this is where all the power is going to go so the is open property changed let's check if is open is true so if it is then we actually want to do the opening animation so we'll encapsulate all of that into a function as well we'll call this open menu and open menu animated so this is going to do all the animation for opening and we'll generate that but then if we're now closed then we'll want to do close menu animated and generate that as well so we're doing well so far and now for the actual animation and this is so much easier than storyboards and control templates so first we're going to define the animation we want to do so in this case animating with width is a double so we're going to use a double animation import that and this is the opening animation and we'll instantiate this and we get a few constructors here so we can pass in the two value the duration the from value as well but i think what we want is this two value so we'll just hard code something for now but in a little bit we're going to show off how we can calculate this 2 value to actually fit the size that we need for our opened hamburger menu and then for the duration i could just hard code that but let's get that passed in as a dependency property so we can configure it that's always fun so another prop dp we'll call this the open close duration property so we'll also use this for closing it'll be of type duration on the hamburger menu and by default i think duration automatic is pretty good that might be too slow or fast but we'll see but anyways now that we have this dependency property we can use that for our duration for the animation and now we want to actually do the animation so ui element which we inherit from somewhere up the chain that has a begin animation function and we can simply pass in the dependency property we want to animate and that is the width property and then we just pass in our animation and that is so much easier we didn't have to deal with any kind of weird bindings and now for the close animation let's change this call this the closing animation and this time the two value is going to be 0. so if the width is 0 it's not going to be visible and i also want to go over why i'm using this 2 value and duration constructor and not the one that wants a from value and that's because i want the from value to be whatever width we're currently at so if i set the from value to something like 100 and let's say that i close while i'm in the middle of opening then i might only be halfway through opening and the current width would be 50 but if we start this close animation then it's going to automatically snap the width to 100 and then start closing and that's not what we want we want the animation to start from 50 what we were currently at when we were opening so we're not going to care about the from value it's just going to be whatever width we're currently at when the animation starts and this is actually everything i think we need so let's go ahead and test this out and here we go our hamburger menu is visible let's click this and we do get an exception so we cannot animate the width property on our hamburger menu and why is that because our width is nan so not a number when we start the animation and that is true because we don't specify a width anywhere on this hamburger menu so by default it's auto which is not a number and honestly we don't really want it to be not a number anyways because by default our hamburger menu is closed so is open is false so we'd really want the width to be zero so in fact what i'm gonna do inside of my constructor so right when we initialize this is set the width to zero and now we should be good so we're closed by default and now we open and there we go that was a pretty slow animation let's go ahead and speed that up so set that duration property the open close duration maybe 0.1 seconds that's faster i think that's like really fast a little bit slower we'll go with like 0.25 that's pretty solid but anyways as we can see we are hard coding our width for this animation to a hundred and that is not big enough for the content inside of the hamburger menu so we could just like increase this to like 300 and then that would probably fit our content but then what if our content got bigger than that we'd have to change this again so really what i'd want is this number that we pass into the animation to just be the size that we actually need for our content so we're gonna have to calculate what width our content actually needs and we can use our content dependency property to do that but we can't do it the way that we have it now because it's just an object if we want to get the width that this content needs it's actually gonna have to be a framework element and then we can access some more properties that'll tell us about the width that it wants so let's change all that and this will still work because a text block is indeed a framework element as most wpf controls are so now content is a framework element so now we can use that down here to get the width that's going to fit our content and that's going to be the contents desired size width it's that simple and let's put that into a variable so the content width and just pass that in as our width so this should all work right let's try it out and let's put a breakpoint here to see what the desired width is and open that and the desired width is zero so that is not what we want and we wouldn't expect that because we know we have content in there so y is the desired width zero well that is because our hamburger menu's width is zero so the content thinks it needs to be zero but we know the content can do better than that we know that content wants to just spread its wings like a butterfly and be its maximum width so we're gonna tell it you know what you can you can be your maximum width and to do that we're going to use the measure function and just tell this content that it can be as big as it wants so we'll pass in a size and we'll just pass in the max width and the max height for the hamburger menu so okay maybe it can't be as big as it wants but it can be as big as the hamburger menu allows it to be and if we don't specify these values on the hamburger menu it's just going to be positive infinity so by default the content can be as big as it wants and this might seem like some kind of hack but this is actually what wpf uses under the hood to measure elements and lay them out on the screen we're just doing it manually and let's see it in action so let's open and now the content width is 127 pixels that sounds about right and we're passing that in so let's see this and there we go we did open i won't actually see it without a break point let's see it and open there we go looks pretty dang awesome and now let's make this text block gigantically long and try this again and there we go we got the full width so the nice thing about our hamburger menu is that it's extremely flexible so for this content we can put in anything we want it doesn't have to be for example hamburger menu items or anything it could be an image it could be like a paragraph a text it can be anything but for this demo i think i actually do want some hamburger menu items inside of here so i am going to create a new control the hamburger menu item and i think i actually want to inherit from radio button because a hamburger menu item can be selected similar to a radio button and then we could group multiple hamburger menu items into a single radio button group so that only one of these hamburger menu items could be selected at once so that could be useful and let's start off by overriding the default style so we're going to take this static constructor that we have in hamburger menu and just copy it into hamburger menu item and update these names import the metadata and now we can define a custom default style for the hamburger menu item and that's going to go in generic.xml so i'm just going to copy the hamburger menu style update this for the hamburger menu item i suppose we don't need this converter anymore same with the hamburger menu don't need it there either and that's actually all i want to do for the hamburger menu item and this might seem like we did nothing but the default control template for a radio button is obviously going to have the actual radio button dot that we select and we don't really want that that would look kind of ugly if we had the actual radio button off to the side here and we had to click that so now back in our main window let's set up our content we're going to put all these hamburger menu items into a stack panel and let's just toss some margin on here we'll do 10 top and bottom and get rid of this old text block because now we are using the mighty hamburger menu item and we can set some content inside of here so we'll just throw another text block in there i guess bring back the introduction text and let's get a few of these i guess we'll do like four maybe five and we'll put some of these names in here so like getting started developer guides tutorials and reference all right that's a good start but we need some padding definitely and we need our font size back so i could apply that to all of these hamburger menu items but instead we'll just create a style in our hamburger menu of resources that's automatically going to get applied to all of these items so we'll define a style targeting the hamburger menu item and we'll set the padding maybe 20 on left and right and then 10 top bottom and we want the font size to be 16. i think that's what we were using before let me just restart let's see how this looks and i'm not seeing the padding so why is that you know what i think oh it's because our border does not template bind to padding so i got to remember all these template bindings this wasn't actually added automatically for us because this original border was just generated automatically in our generic.xml we just used it and then eventually copied it down here so i blame the wpf template for that but that should fix it okay that's good and now we have to open and close again because our content changed there we go that's much better and now let's get some of this hover action animation going in here so it looks like by default we have a slightly different font color and i believe that is let's see what is that looks like four four four in hex so we'll set that as the foreground color this is just turned into recreating the angular hamburger menu okay that looks good so looks like the font color that's not really an animation i think that's just an immediate change that's going to be pretty easy to implement and for that we can set some triggers in here and when you set a trigger for if is mouse server is true then we'll set the foreground color to that blue stuff and what is that blue stuff so 1 6 6 9 bb copy that it looks like that's also the color whenever the hamburger menu item is selected so we can also have a trigger for is it's gonna say is selected but it looks like it is checked because we inherit from radio button and now look at that that looks good and okay when we hover over it it changes as well so we're getting there now we just need the background and those can be event triggers and the event we want to use is mouse enters so whenever our mouse enters the bounds of the hamburger menu item then we want to start a animation and we are going to use storyboards for this this is pretty straightforward so no worries and we'll just throw a storyboard in here and we're animating the background color so this is going to be a color animation and the duration i guess we'll just do like point one second seems pretty fast and then the color we're animating to is the good old dbdb db and then the property we're animating so we access that with storyboard target property this one's a little bit weird so it is the background but background is a brush and we're using a color animation so we want to grab the brush that's set on our background and animate that brush's color so to access that brush we're gonna have to do some casting so we can surround this with parentheses and then grab the color on the background and that is a solid color brush and let's see if this actually works with live debugging we might have to restart but hover over and we actually crash and we do not point to a dependency object and i think the reason for that is because by default the background is not set so we do have to give it a default value and we can set that to transparent and i think that should work so let's hover all right there we go so now we just need to remove that background color whenever we leave so for that we just copy the event trigger change it to mouse leave and we're just going to animate back to transparent and all right i think this time we do have to restart let's try this again oh that's going to be good there we go looks pretty awesome and as we can see on the angular page we do have these drop downs and i'm not going to go into that because i'm going to save drop downs for another ui component workshop so saving that for now i don't want this video to go on for too long which i think it already has but that is where we're going to wrap up so we have our hamburger menu we started off without animation and that was pretty simple but to add animation not too bad considering we use the code to animate and even if we didn't want the animation we could just set the open closed duration to zero so look at that all right no more animation but i like the animation that's fun and then we can pass in any kind of content to our hamburger menu in this case we have these custom hamburger menu items which just inherit from radio button and we have some styling everywhere to give it the angular hamburger menu look and feel and real quick i know there's something dangerous so what if the content was null so in that case let's go into our main window and just comment out all the content well then we get a null reference exception that's not what we want so what we should do is let's just move all of this with calculation into a function so we'll call this get desired content with and we can just say if the content is null then return some kind of default value maybe 100 or how about a fallback width and that can be a dependency property that the client can set so the fallback how about the fallback open with and that's a double the inner class is the hamburger menu and the default value we'll just make it a hundred whoops this is supposed to be fallback open with make sure i change all that and then use that as the fallback value and we'll set that we'll say maybe 300 so kind of big and try this out so even though the content is not we still open successfully so that's where we're going to wrap up hamburger menu is definitely a beautiful ui component to add to your own application so maybe you could use this hamburger menu as the jelly to the peanut butter of my navigation series if you have any questions criticisms or concerns be sure to leave them below in the comments section if you're enjoying the channel or enjoyed the video consider becoming a member other than that leave a like or subscribe for more thank you
Info
Channel: SingletonSean
Views: 3,036
Rating: undefined out of 5
Keywords: wpf, programming, visual, studio, xaml, custom, control, generic, system, line, display, timer, template, binding, c#, how, to, series, tutorial, easy, time, package, design, part, event, code, framework, register, static, state, default, style, wrap, panel, stack, scroll, viewer, first, width, command, handling, action, task, void, model, layout, user, box, error, icon, class, relay, clean, simple, log, file, host, grid, shared, size, scope, align, margin, deploy, release, download, dependency, property, advanced, learn, skill, hamburger, menu, drawer, slider, item
Id: mjYXnlufyI8
Channel Id: undefined
Length: 23min 1sec (1381 seconds)
Published: Sat Aug 21 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.