In the previous tutorials, we have learnt about basic controls, their positioning and their placement within panel controls. In this tutorial, we are going to tackle some slightly advanced controls and their usage. These controls, in conjunction with panels and other classes, aid in advanced and intelligent layout creation. Some commonly used slightly advanced controls include TabControl, GroupBox, Menu and Expander. We are going to study each of these in further detail now.
Let us start with the TabControl. A TabControl is a control that allows you to build tabbed items. Basically, it is a collection of TabItems. Each TabItem is like a collection of items or a page in itself. A TabItem has two main properties. First is the header that tells what the header of the tab will be and second is the “IsSelected” property that defines which tab is selected from the collection. If this property is not set, then the first tab is selected by default. So, let us define a page with the TabControl as follows:
Within this, we place 3 items, first one having a grid with 2 buttons, second one having an image and third one empty as shown:
<Button Height=”50px” Width=”50px”>Hello1</Button>
<Button Height=”50px” Width=”50px” Grid.Column=”1″>Hello2</Button>
<TabItem Header=”Second” IsSelected=”True”>
As you can see, the contents of a TabItem are not limited to anything specific. It can be a control, a group of controls arranged within a panel or a mix of panels and controls. The output will look like this:
The second tab is selected initially as we have set the IsSelected=”true” for it.We can change the positioning of the tabs by choosing different values like left, right or bottom for the TabStripPlacement property (default is top). You can also create context menus for each of the TabItems in the TabControl. There is a very simple example that you can refer to here.
In talking about TabControl, we can also understand the working of TabPanel which we excluded in the last tutorial. A TabPanel is a panel that provides an area to lay out TabControl’s items. Having a container can be useful, for example when you want to control the layout of the TabControl and all its children as a whole, or when you want to restrict the tab items into a specific area within the layout. However, most of the times you won’t probably be needing a TabPanel while using TabItems as the TabControl will suffice.
The second advanced control we are going to tackle is the GroupBox. This is in fact a personal favourite of mine. It is basically a control that groups other controls into an area with a header. The header of the area is specified by the Header property of the groupbox. So, for example, let us say we put a TabPanel over the TabControl and wrap everything within a GroupBox with a header as below:
<GroupBox Header=”This is a Tabbed Page” Margin=”10,10,10,10″ FontSize=”16″ Background=”LightGray”>
Now, this is how the output will look like:
The grey area with the header (This is a Tabbed Page) is the Groupbox. It can give a pleasing visual appearance when you want to group related controls under one group with a common header.
The third advanced control we will tackle is the Menu control. It is similar to TabControl in that you can add multiple items and sub-items to the main control. However, while tabs may represent different pages, menus are more like toolbar options that provide various functionalities. Think of notepad with different menus at the top like “New”, “Edit” and “View” each with sub-options – the menu control provides a way to create all these options and suboptions. The Menu control has MenuItems and each MenuItem has a Header that tells what the option is called. Under each MenuItem, you can have further MenuItems thus creating heirarchical menus. This means that you can provide lot of different features within very less space. So, if we want to create something similar to a notepad menu, this is what we do:
This will give you a cool looking menu bar with 3 main options called “New”, “Open” and “Save”. “New” will further have 2 sub-items called “Open” and “Save”:
A cool feature of the menu control is that you can add images next to menu items and also shortcuts. Suppose you want to add a sub-menu called “Cut” under “Edit”, put an image of a scissor next to it and assign it a shortcut called “ctrl+c” to it, it is pretty easy to do it. First you add another MenuItem under the “Edit” MenuItem. Then, to add a image, you need to set the property MenuItem.Icon for it and put an image under it. This image will appear to the left side of the menu item’s header. To set the shortcut, we need to use “Command”. This has the big advantage of making the keyboard shortcuts generic without having to write a lot of code, and also by using commands, you can make WPF respond to keyboard shortcuts automatically (which it otherwise doesn’t do). And the best part is that when it comes to some pre-defined commands like cut, copy, paste etc, we don’t even have to handle their execute events. WPF does everything. So, if you want the shortcut for “Cut” (which is predefined as ctrl+x), all you need to do is define Command=”Cut” on the MenuItem as shown:
<MenuItem Header=”Cut” Command=”Cut”>
<Image Source=”./Images/Scissor.jpg” Height=”20px” Width=”20px”></Image>
Now you just have to combine this block with the earlier one, set some visual properties like height and columns, add a textblock to accept user input as: <TextBox AcceptsReturn=”True” Name=”txtEditor” Grid.Row=”1″/>. When you run it, this is what you see on screen:
As you can see, the icon and the shortcuts are all there. The menu option is disabled because right now nothing is selected for cutting. This is another advantage of using commands. WPF handles the state autmatically based on the functionality of the menu. So, if you type some text and select it, then the option is enabled as shown:
When you select the “Cut” option, since the command is pre-defined, the text gets cut. In other words, it works exactly as it should without you doing anything to handle the command execution. However, if the command is something new then we have to handle it u through commandbindings but more of that later. Instead of the image icon, you can also have a check next to the menu by setting IsCheckable = “True” and IsChecked=”True” for any MenuItem so that you can toggle the options.
Another cool feature in the above scenario is the use of accelerator keys. Do you notice the “_”(underscore) before the “Edit” header? It basically tells WPF to use “E” as an accelarator/access key for the edit menu. It means that if you press Alt and then E, the edit menu is activated. The same works for other menu options as well. Overall, you get a lot of free things for little effort using the Menu control.
Now coming to the fourth type of advanced control, the Expander control is similar to a Groupbox with the difference being that it allows you to expand or collapse the content. It has a Header similar to Groupbox and the content under it can be collapsed or expanded. So, replacing the GroupBox in the TabControl example with the Expander control will give the following results:
The main advantage of the Expander, apart form the fact that the content can be collapsed is that in collapsed state, it takes only the space needed for the expander control. This means the rest of the space is free. By default the content under the Expander control is collapsed but it can be set to expanded state by setting IsExpanded=”True”. You can also specify the direction in which the expansion or collision happens by setting ExpandDirection. You can also link events to expansion and/or collision by using “Expanded” and “Collapsed” event triggers. So, that’s the Expander in a nutshell.
Finally, let us say you you want to extend a control’s functionality or appearance. This is accomplished by using special classes of controls that are derived from the base class “decorator”. As the name implies, they are mostly used for decorative visual purpose or to extend functionality of existing controls. A decorative control always has one child control that it “decorates” although that child can be a panel control that contains several other controls. One type of decorative control is the border control that draws a border around a control. We have already seen this in action in case of the Fontviewer application. A Border can surround any child control such that it can either create a decorative effect or hide some aspect that you do not wish to display.
Another commonly used decorator is the ViewBox. The ViewBox is a very simple but highly effective decorator control that causes the content to scale in order to fit the available space. Meaning the content resizes when you resize the control. For example, let us place a button inside a canvas as below:
<Canvas Width=”500px” Height=”500px” Background=”AliceBlue”>
<Button Height=”100px” Width=”100px” Canvas.Top=”100px” Canvas.Left=”100px”>Hello</Button>
When you run this, you will see that a blank canvas with blue background is rendered with a button in the specified position. Now try to resize the window and as it becomes smaller, this is what will happen:
As you can see, the content (in this case, the button with its text) has remained same in size, causing it to be chopped off when the window becomes very small. Now, surround the Canvas with a Viewbox:
Now, when you run the program, and resize the window, this is what you will see:
As you see, the content also gets resized according to available space when you use the viewbox. This is very nice and useful behaviour. Now, let us surround this with a nice border of variable thickness as <Border BorderThickness=”2 8 2 8″ BorderBrush=”Red” CornerRadius=”20″>. Change the button height and positioning a bit, and this is the overall effect:
We have seen just the basic usage of the Border and ViewBox controls in the above example. They have many other properties that provide control over their appearance and behaviour. For instance, by using properties like Background, Effect and Margin, you can further alter the appearance of a border. Similarly, by using the StretchDirection and Stretch properties of ViewBox, you can control how the content is scaled. It is however, important not to get too taken in by the different options or else you will get overwhelmed. At the same time, do not be scared to mix and match or experiment. Start with simple layouts first and use advanced controls or properties when necessary. Also, while we have demonstrated the use of properties like height and width using hardcoded values in the examples for the sake of simplicity, try to avoid hardcoded values in real-life applications. Instead try to keep the layout and positioning as flexible as possible so that it renders well on different monitor-sizes and resolutions. Overall, remember that clean, flexible, judicious layouts score any day over cluttered, overcrowded ones that have too much going on.