Well it’s not exactly my first, but might as well be. Aside from playing around with WPF a couple of times, I’ve never really sat down and written an application from start to finish. Hopefully, this will be one time where I do finish.
Given a set of requirements that contains a series of screens, I am to implement a wizard like interface. Since this application is targeting external customers, looks will count for something. I also want to make sure that there is no confusion between the old application and this new version of the application.
To start with, I have installed Expression Studio 3, along with the WPF themes from the WPF toolkit. The themes are part of the WPF futures release in the WPF toolkit project on CodePlex. I then created a new WPF application in Visual Studio (since I was waiting for Expression to download and install) and added the Expression dark theme to my App.Xaml file as a resource dictionary (key section is in bold below). You can see in the source attribute, that I have added themes folder that will contain all of the downloaded themes. I then switched to Expression Blend 3 to begin work on the UI in earnest.
<Application x:Class="ThemesSample.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
StartupUri="Window1.xaml">
<Application.Resources>
<ResourceDictionary Source="Themes\ExpressionDark.xaml"/>
</Application.Resources>
</Application>
As I am a firm believer in not re-inventing a wheel, a quick Bing search gave me some possible WPF wizard implementations. There were a couple of pay options, and one open source option, Piotr Wlodek’s WPF Wizard Control. His sample application and code looked pretty straight forward and I was fairly certain I could massage it into my application without too many problems.
After downloading and extracting the WPF Wizard Control, I was presented with three projects. Pitor’s post uses the code in the WPF Wizard 2 project, so I started there as well. The base control is named Wizard and is in the controls folder. So I created a controls folder in my project as well, and imported Wizard.cs by using the Add Existing Item option in Blend and updated the namespace to match my project.
Next I deleted the MainWindow.xaml file that was created with my new project, and imported the Window1.xaml from the WPF Wizard 2 project. Again, I had to go thru and update the namespace in the code behind file, as well as change the class name in Window1.xaml from WpfWizard to MyNamingConvention.Window1. You will also need to update the reference to Controls on line 4 in Window1.xaml to match your namespace. Once finished, you should be able to build, and see an empty white window in the designer for Window1.
So where is the Wizard? Well, the original project uses a Generic.Xaml file to define the styles of the various UI elements. Since we haven't imported that yet, we don’t see anything. The problem that we need to solve is “merging” the Generic.xaml from the Wpf Wizard project with our themes that we downloaded. I wanted to show you what the application looked like at this point, because I think it shows how WPF operates differently from other types of applications.
In order to have a good starting point, I went ahead and imported the Generic.xaml file from the Wpf Wizard project, and updated the namespace on line 3. After rebuilding, I now start to see some actual UI elements on Window1. You should also note that the check box on the side bar is in fact picking up our ExpressionDark theme. However, the buttons are not picking up the theme, and the background is certainly not appropriate for our ExpressDark theme.
To fix the buttons, I went ahead and removed the style property for each button in Generic.xml, and manually set the margins and width on each button. This allows the buttons to pick up the style from ExpressionDark. There is a way to do some style inheritance, but at this point I don’t think I need it for the buttons. However, you can add the following attribute to the a style tag: BasedOn="{StaticResource {x:Type Button}}” – See this post for more information on the BasedOn attribute.
The background color for the wizard was really giving me problems, so I decided to skip it for now and add the rest of the my wizard pages so I could test that out. Switching back to Window1.xaml (view XAML), you will see that the wizard is made up of a Wizard control tag, and then 1 or more WizardPage child controls (see image below). The hierarchy is:
- Wizard
- WizardPage (CanFinish, CanCancel)
- SideHeader: Option. I’m using it to show progress thru the Wizard
- Border: Main content and additional controls go here
I created my first page, complete with a stack panel in the SideHeader, which contains 6 labels to indicate which step of the Wizard we are on. I then copied and pasted the <WizardPage> 5 times, changed the comment before each page, and updated the label names to get my basic 6 screen wizard. The CanCancel attribute on the Wizard page is set to true by default, so I left that as is, and since I only want someone to be able to finish after getting to the last screen, I set CanFinish to true on the 6th <WizardPage>.
I went back to the background color and finally figured out that you need to change the styles defined in Window1.xaml, not Generic.xaml for:
- x:Key="{x:Static Controls:Wizard.HeaderPanelBorderResourceKey}"
- x:Key="{x:Static Controls:Wizard.SideHeaderPanelBorderResourceKey}"
- x:Key="{x:Static Controls:Wizard.NavigationPanelBorderResourceKey}"
- x:Key="{x:Static Controls:Wizard.ContentPanelBorderResourceKey}"
I’m going to assume that since the styles were defined in two locations, the one in Window1.xaml takes precedence. The styles in Generic.xaml are either there as defaults, or were unintentionally left there by the original author.
My final touch, was to define a second style for my ProgressLabels, called ProgressLabelSelected, which changes the foreground color. When not selected the label is black, when selected the label is white. Here is what Window1.xaml now looks for me after the background and label changes, and I think it’s coming along nicely.
One thing that I do not like about this wizard control, but is present in almost any wizard control I have used, is that it’s difficult to work with the various wizard screens. While you can edit the xaml directly, that is kind of a pain and gives no design time view. Hiding the WizardPage doesn’t work, and so far my only option is to drag the wizard page I want to work with to the top of the list.
I think I’m at a good spot to leave off at for this post as I move onto adding more controls and content to the various Wizard Pages. I’ll come back with a second post on what I learn during that process.