Virtual Developer Workshop: Containerized Development with Docker
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).