In the first article of this series, I introduced Windows Presentation Foundation that is part of WinFX, the new API for Windows Vista, XAML, a new descriptive XML-based language for designing user interfaces and 'Cider' the Designer for Visual Studio 'Orcas', and you built a small calculator application with XAML. In the second article, I gave you an overview of the Microsoft Expression family (Graphic Designer, Interactive Designer, and Web Designer). In this article, you'll see the first two tools of the family at work to change the user interface of the XAMLCalculator application from the first article.
Before going any further, I strongly suggest you to go through the first two articles, especially if you are not familiar with WPF, XAML, and the Microsoft Expression family of tools. For this article, you'll have to install all the required betas indicated in the first two articles.
Let me point out that the goal of this article is to get familiar with different aspects of the Graphic and Interactive designer and not to build an application with state-of the art user interface and functionality. Here is how the final application will look:
Creating the Graphic Elements with the Expression Graphic Designer
As already stated, in this article you'll give a complete face-lift to the XAML Calculator created in the first article. One important aspect of this face-lifting is customizing the buttons of the calculator. What I want to do is use some hand-written characters to be displayed in the buttons; here is where the Expression Graphic Designer comes into action. However, I want to keep things simple, so I'm not going to do very complicated things.
Start by opening the Expression Graphic Designer and create a new vector-based document. At this point, you should have a list of toolboxes opened on the right side. Make sure you have Toolbox, Paint Style, Attributes/Effects, and Stroke/Brush List windows opened. If they are not there, go to Window and select them.
Because you want to write some characters and symbols, select the Freehand Pen (P) from the Toolbox. In the Paint Style window, select the Skeletal Stroke and adjust the width to, say, 10 points. If you select the Stroke S04 from the Stroke/Brush list, your Paint Style window should look like this:
Next, you will write the symbols inside the document window. If you have a graphic pen, it's great (especially because the Expression Graphic Designer is pressure sensitive), but even a mouse will do just fine. Basically, you need to write the following characters and symbols:
Some of these symbols were made with several strokes. For instance, the + or * symbols or the word "back". If you select the "+/-" symbol, you can see the selection of each individual object:
You need these objects merged into a single object. For that, you will use the command Object > Compound Object > Make. After merging the objects, the selection will look like this:
Just make sure you repeat the same operation for all compound objects (7, +, *, +/-, and Back).
At this point, you have all the symbols you need, but I want to give them a better look. So, I'm going to add a shadow. For that, first select an object—for instance, the symbol 1—and open the fx tab of the Attributes/Effects window, and use the + button to select the shadow.
Adjust the different settings of the shadow, especially the Offset, so that it drops just behind the object, and the color, to a dark green.
Obviously, you want to apply the exact same settings to all the objects. With the Expression Graphic Designer, it's very easy to do it: If you select all the objects, you'll see that the Drop Shadow effect in the Attributes/Effects window has been disabled, but it's still there. You only have to click it twice, and it will be enabled, but this time for all the selected objects. So, your objects will look like this:
The last thing left to do is to save this to XAML. For that, go to File > Export > XAML Export and select a name for the file. After pressing Save, the Designer shows a window were you can choose different settings. Here, you can see a preview of the exported objects and the generated XAML code. What you want is to save the document as a Resource Dictionary, grouped by Objects with Drawing Brushes for Path Output Type. In the preview area, you can see each individual object that is selected. Before proceeding with the export, make sure the background is set to Transparent and all the checkboxes in the Effects tab are selected. If you look on the disk, you'll see the XAML file and a folder containing a list of PNG files that contain the symbols.
This is all the work you have to do in the Graphic Designer. Now, you will import this in the Interactive designer and use it to customize the calculator's aspect.
Creating the Application with the Expression Interactive Designer
Getting Started with the Interactive Designer
The next step is to create an empty standard application in the Interactive designer. For that, you have to use the File > New Project command and select Standard Application (.exe) with C# as the language for the code-behind files. I have named the project XAMLCalculatorArt.
At this point, you have an application (Application.xaml with the code-behind file Application.xaml.cs) and a default empty scene inserted, called Scene1, located in Scene1.xaml with the code-behind file Scene1.xaml.cs. This scene will be the host of your calculator interface (and you'll change its name later).
Let me remind you that the point of this exercise is to get familiar with some elements of the Interactive Designer and several WPF controls and not to build a state-of-the-art calculator. So, you'll keep things as simple as possible (but not simpler).
On the right side of the designer, you can see a series of windows, such as Tools, Libraries, Projects, and Properties. You will use several of these windows, and if you don't already have them open there, you can show or hide them from the View menu.
Under the art-board that displays the empty scene, there is the Timeline window that shows a tree of the controls in the scene. For the empty scene, there is a single element, called DocumentRoot, of type Grid. This will be the container for all the controls that you place inside this scene.
You can divide the scene in any number of rows and columns you want. To do that, open the Tools window and choose the Selection (V) pointer. In the art-board, you can see two thick blue bars on the top and left of the scene area. If you hoover the mouse over them, a red line is shown. That will define a row or column separator if you click with the mouse on the blue bar. What I want to do is create two rows to separate the textbox that will show the numbers and the buttons of the calculator.
You can see the horizontal separator in the picture above. You also can see the text box that I've placed into the scene. The controls are available from the Library window. You can select it and then draw it into the scene. You also can double-click it in the Library window and a control with a default size will be placed automatically into the scene as a child of the current selected element in the Timeline's tree. When you draw the text box, it will lock automatically to the nearest line separator (or margins), as you can see in the picture with the small black locks. My intention is to space the text box equally into the upper row. You can use the Layout window for that.
Under the Margin tab, select the Alignment to Stretch (as shown in the picture) and set the distance to the Top, Left, Right, and Bottom margins (I set it to 20 pixels). The result is that, when you resize the window, the text box will be resized automatically to maintain that distance to the window's margins. (You can test that at any point by simply pressing F5 and running the application.)
The next thing I want to do is create a gradient background for the scene. You can use the rectangle basic shape, available from the Tools window, for that. I drew this rectangle over the entire scene area, but I want it to fill the whole scene area exactly. So, you can repeat the same operation in the Layout window, setting the Alignment to Stretch and the distance to the margins to 0 pixels. As for setting the gradient fill, the Appearance window will allow you to customize it.
From this window, you can visually set some basic appearance properties (that are also displayed in the Properties window). What I want is a gradient green to white, just as it's shown in the picture above. As you make changes here, you automatically can see the look of the control in the art-board.
If you added the rectangle after the text box, it will be placed over it. But, make sure the rectangle is the bottom control in the scene. Drag and drop it in the Timeline's tree at the bottom of the tree (as shown in the next picture).
As I said earlier, I want to separate the buttons from the text box, but I also want to separate the buttons in two groups: one represented by the ten digits, equal, and sign buttons, and one with the rest of the buttons. To do that, I'll just add a column separator, as shown in the picture above.
Before adding any buttons, I will place a Grid control in both of the two lower columns and I will rename them (from the Properties window) to LeftGrid and RightGrid. Moreover, inside each grid, I will add a WrapPanel control that provides automatic layout for all the controls placed inside it. In the image above, you can see the LeftWrapPanel selected, and the next picture shows the Timeline tree with the controls you have so far:
Now, everything is set to start adding buttons. Before doing that, double-click the LeftWrapPanel in the tree so that it becomes the active selected control (shown with a yellow wrapping rectangle). Choose the Button control from the Library window and draw a square button in the wrap panel. You can notice that is displayed automatically in the top-left corner; if you try to move it any other place, you'll not be able to because of the automatic layout this WrapPanel control provides. You don't want this button to be very big, so I'll set the size to 60 pixels (both for width and height). You can do that from the Layout window, Size tab.
Creating a Control Template
The button that you placed into the scene is a default one, with a chrome gradient and a default font for text. I want to change all that and use the artwork symbols created with the Graphic Designer. Fortunately, that is easy to do because the controls use a template and this template can be changed. So, go ahead and create a new template for your buttons. For that, select the button and right-click it. From the Context Menu, select Edit Template > Edit a Copy of the Template command. (You can't change the original WPF template, but you can create a copy of it and edit that one.) A window with several options is displayed:
I've named the template ArtButtonTemplate and kept all default values for the rest of the options. After pressing OK, the Timeline window changes to the one shown in the next picture.
On the left, there is the tree of controls that define the template. You can see a Chrome control that gives that chrome gradient to the button and a ContentPresenter that can host almost any media content (such as text, bitmaps, animations, and movies). On the right side of the window, you can see a list tab buttons, such as IsKeyboard, IsMouseOver, IsPressed, and so forth. These are the different possible states of the button, and you can have different template settings for each individual state.
With the None button selected, delete the Chrome element (the child ContentPresenter also will be deleted automatically). Instead, you will add a Grid control that will host a rectangle (to have a background for the button) and a ContentPresenter to host the symbols you created with the Graphic Designer. Eventually, the template tree will look like this:
The first element that you add is the rectangle. I want it to be almost as large as the button, but still keep a short distance to the margins, so I'll use the Layout window to set the alignment to Stretch and the margin distances to 3 pixels. But, I also want it to have curved corners, so I'll use the small rounding elements you can see in the following image to adjust that:
I want this background rectangle to be transparent, so I'll set the Opacity to a low value, like 20%.
Second, you'll add a ContentPresenter and set the margins to 0 pixels. you are going to change that later as well, as defining different settings for different states, but for the moment you are done with the new template for the button. To return, press the Return Scope to Root button in the Timeline window (fourth from left to right).
At this point, you have a button inside the LeftWrapPanel control, but you need 12 here and six in the RightWrapPanel. You can create them by simply copy/pasting the first one. However, make sure that the appropriate wrap control is selected so that the new added buttons are children of that control. After adding all the buttons, the scene should look like this:
As you can see, the ContentPresenter that you added to the button template automatically detected that it is part of a button control and, because no content is put inside it, a default "Button" text is displayed.
Using the Graphics Created with the Graphic Designer
Now, you will import the images you created with the Graphic Designer. For than, use the Project > Add Existing Item command and import all the PNG files. After the import, the Projects window should look like this (notice that I also added the symbols.xaml resource dictionary file):
Before continuing, I changed the default names of the buttons to new ones to indicate what each button of the calculator actually is (you can see the tree in the next image).
There are several ways to put the images inside the buttons. One way is to use the Insert Into Scene command that will place the image inside the currently selected element. The second way is to double-click the image in the Projects window. If you select the Button7 control and double-click the image6.png file, the symbol 7 will be put inside the button automatically, hosted in the ContentPresenter control (the image above already shows this). If the WrapPanel control is selected, the image will be put inside this control, but it can be moved inside a child button by dragging it with the mouse. As it is hovered over a control that can host it, a selection rectangle is displayed and the text "ALT-drag to place inside" is shown. Press the ALT key and release the mouse button to place it inside that control.
After repeating this operation for all the buttons in your scene, it should eventually look like this:
Editing the Custom Button Template
However, there is one thing I'm not satisfied with: the symbols placed inside the buttons seem to get out of the bounding rectangle and I want to change that. Additionally, I want to customize the look of the buttons for the IsMouseOver and IsPressed states, so I'll go and change the template for the button. This time, use the Edit Template > Edit Template command from the context menu of the button. Because all the buttons were copied/pasted from the first one, they all share the same template, and changing the template for one button will change all the buttons in our scene automatically.
First, select the None state button, and for the ContentPresenter set the margins to 5 pixels.
Second, select the IsMouseOver button and for the rectangle change the gradient fill to a yellowish gradient, but increase the Opacity to 70%. Also, I want the bounding stroke to be 2 pixels in width and have a yellow color. You can set the stroke width from the Stroke window:
Last, select the IsPressed state button and for the rectangle set the Fill to none (No Brush), and the opacity to 20% again. For the ContentPresenter, I want the distance to the margins to be bigger, like 10 pixels. That way, when the button is pressed you'll see the symbol shrinking, which will give a small animation effect, as you can see below:
To return, use the Return Scope to Root Button.
The last change that I want to do to the user interface is to set the Background for the text box to No Brush, so that it will use the background of the control behind it (the gradient rectangle).
Adding the Business Logic
So far, you have designed the user interface. The only thing left to do is add the business logic. Because I already created the business logic for a calculator in the first article of the series, I want to reuse that. But before, I have to prepare the current project.
The first thing I have to do is change the name of the Scene1 scene to XAMLCalculatorWindow (XAMLCalculatorWindow.xaml and XAMLCalculatorWindow.xaml.cs for the code behind window). Your project namespace also has to change to XAMLCalculator to match the one of the first project.
In the XAML code for the scene, I'll change the x:Class attribute to XAMLCalculator.CalculatorWindow:
Also in Application.xaml, I have to change the same attribute as well as the StartupUri so that they look like this:
In the Application.xaml.cs code-behind file, I changed the name of the namespace to the same XAMLCalculator. What I want to do is copy/paste the former XAMLCalculatorWindow.xaml.cs from the first project to this one. Before doing that, open the Events window and add a handler for the Click event for each button. Call the events OnButton0Click to OnButton9Click, OnButtonSignClick, OnButtonEqualClick, OnButtonClearClick, OnButtonBackClick, OnButtonAddClick, OnButtonSubClick, OnButtonMulClick, and OnButtonDivClick. By doing this, the designer adds an attribute in the XAML code indicating what event handler from the code-behind class will handle the click event. Also, it adds an empty handler in the code-behind file, but you'll discard those handlers by copying/pasting the former XAMLCalculatorWindow.xaml.cs and overriding the project's file.
And with this, everything is set and you can run the application. You can see how the button changes when you hover the mouse over it or when you press a button. Also, you can resize the window and see the buttons inside the wrap panels being repositioned automatically.
In this article, I've shown you how you can create simple graphics in the Graphic Designer and export them to XAML to be used later in the Interactive Designer that you used to create a simple calculator with a different user interface from the one shown in the first article of the series. You have seen how to create rows and columns inside a grid control, how to use a WrapPanel control, and how to create custom templates for controls such as buttons. All in all, you kept things simple, but nevertheless you can see how easy it is with the Expression tools to create rich user interfaces for your applications. In the next articles, the user interfaces will become richer and richer.