Using Expression Blend and Visual States for Image Swapping
For this example, lets think of a stop light during the traffic of your morning commute. There will be three images of a stop light. Each image will have either the red, yellow, or green light on.
Link: I used traffic light images from here: http://www.psdgraphics.com/psd-icons/traffic-lights-icon-psd
*** This can be done 100% in Expression Blend without using any code at all. ***
Note: This is for both Developers and Designers. It is for designers because they can do all of this without code. It is for Developers because they need to know to not go reinvent the wheel and spend their time writing code to do this.
Step 1 – Create a new WPF Application project
You can do this in either Visual Studio or Expression Blend. For this example, we will use Expression Blend 4.
- Open Expression Blend 4.
- Go to File | New Project.
- Choose WPF Application.
- Name the project and click OK.
Note: I named this project SwitchImagesWithVisualStates.
Step 2 – Add Images to the WPF project
- Right-click on your project and choose Add new folder.
- Name the folder Images.
- Open your file system and copy or drag your images to this new folder in Expression Blend.
Note: If you copy the images using the windows file system, you may have to add the files to the project.
Step 3 – Design the View
We are going to have a simple view for this example with the images on the left and buttons on the right.
- Open MainWindow.xaml.
- Add a column to the default Grid, so there are two columns.
- Make the columns 3* and 1*. This will make the left column 75% and the right column 25% of the Grid size.
- Add all thee images to the left column.
- Remove any margins, heights or widths, and vertical or horizontal alignments from the images.
Note: This is important so the images are always in the same place.
Note: This assumes that all three of your images are identically sized and properly placed. - Name each Image: ImageRedLight, ImageYellowLight, ImageGreenLight.
- Add a StackPanel to the right column.
- Remove any margins, heights or widths, and vertical or horizontal alignments from the StackPanel.
- Click to select the StackPanel in the Objects and Timeline box.
- Add three buttons to the StackPanel in the right column.
- Remove any margins, heights or widths, and vertical or horizontal alignments from the buttons.
- Name each button: ButtonRedLight, ButtonYellowLight, ButtonGreenLight.
Your Xaml should look like this:
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" x:Class="SwitchImagesWithVisualStates.MainWindow" x:Name="Window" Title="MainWindow" Width="640" Height="480"> <Grid x:Name="LayoutRoot"> <Grid.ColumnDefinitions> <ColumnDefinition Width="3*"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> <Image Name="ImageRedLight" Source="Images/Red.png" /> <Image Name="ImageYellowLight" Source="Images/Yellow.png" /> <Image Name="ImageGreenLight" Source="Images/Green.png" /> <StackPanel Grid.Column="1"> <Button Name="ButtonRedLight" Content="Red Light"/> <Button Name="ButtonYellowLight" Content="Yellow Light"/> <Button Name="ButtonGreenLight" Content="Green Light"/> </StackPanel> </Grid> </Window>
Step 4 – Add VisualStates in a VisualStateGroup
- In Expression Studio, click on the States tab.
Note: Sometimes the States tab is hard to find. - On the top right of the States tab, click icon that has a + sign to add a VisualStateGroup.
- Name the VisualStateGroup.
Note: I named mine VisualStateGroupTrafficLights. - Under the VisualStateGroup you now have another icon with a + sign (the Add state icon) that add a VisualState to the VisualStateGroup. Click it three times to add three VisualStates.
- Name the VisualStates: VisualStateRedLight, VisualStateYellowLight, VisualStateGreenLight.
Step 5 – Set new values for each VisualState
- Configure the VisualStateRedLight.
- Click on VisualStateRedLight.
- You will see a red outline around the designer and the words: VisualStateRedLight state recording is on.
- In the Objects and Timeline tab, press and hold control and click to select both ImageYellowLight and ImageGreenLight.
- Go to the Properties tab.
- Change the visibility of the images to Hidden.
- Configure the VisualStateYellowLight.
- Click on VisualStateYellowLight.
- You will see a red outline around the designer and the words: VisualStateYellowLight state recording is on.
- In the Objects and Timeline tab, press and hold control and click to select both ImageRedLight and ImageGreenLight.
- Go to the Properties tab.
- Change the visibility of the images to Hidden.
- Configure the VisualStateGreenLight.
- Click on VisualStateGreenLight.
- You will see a red outline around the designer and the words: VisualStateGreenLight state recording is on.
- In the Objects and Timeline tab, press and hold control and click to select both ImageRedLight and ImageYellowLight.
- Go to the Properties tab.
- Change the visibility of the images to Hidden.
Step 6 – Configure each Button to switch to a VisualState on click
- Configure ButtonRedLight.
- In Assets, search for GoToStateAction.
- Click and drag the GoToStateAction and drop it in the designer over the ButtonRedLight.
- Go to Properties.
- Name it GoToRedLightState.
- Set the StateName to VisualStateRedLight.
- Configure ButtonYellowLight.
- In Assets, search for GoToStateAction.
- Click and drag the GoToStateAction and drop it in the designer over the ButtonYellowLight.
- Go to Properties.
- Name it GoToYellowLightState.
- Set the StateName to VisualStateYellowLight.
- Configure ButtonGeenLight.
- In Assets, search for GoToStateAction.
- Click and drag the GoToStateAction and drop it in the designer over the ButtonGreenLight.
- Go to Properties.
- Name it GoToGreenLightState.
- Set the StateName to VisualStateGreenLight.
That is it. You have now written an application that switches the image.
Here is your final Xaml.
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:ei="http://schemas.microsoft.com/expression/2010/interactions" x:Class="SwitchImagesWithVisualStates.MainWindow" x:Name="Window" Title="MainWindow" Width="640" Height="480"> <Grid x:Name="LayoutRoot"> <VisualStateManager.VisualStateGroups> <VisualStateGroup x:Name="VisualStateGroupTrafficLights"> <VisualState x:Name="VisualStateRedLight"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageYellowLight"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageGreenLight"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="VisualStateYellowLight"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageRedLight"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageGreenLight"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> <VisualState x:Name="VisualStateGreenLight"> <Storyboard> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageRedLight"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/> </ObjectAnimationUsingKeyFrames> <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ImageYellowLight"> <DiscreteObjectKeyFrame KeyTime="0" Value="{x:Static Visibility.Hidden}"/> </ObjectAnimationUsingKeyFrames> </Storyboard> </VisualState> </VisualStateGroup> </VisualStateManager.VisualStateGroups> <Grid.ColumnDefinitions> <ColumnDefinition Width="3*"/> <ColumnDefinition Width="1*"/> </Grid.ColumnDefinitions> <Image x:Name="ImageRedLight" Source="Images/Red.png" /> <Image x:Name="ImageYellowLight" Source="Images/Yellow.png" /> <Image x:Name="ImageGreenLight" Source="Images/Green.png" /> <StackPanel Grid.Column="1"> <Button x:Name="ButtonRedLight" Content="Red Light"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <ei:GoToStateAction x:Name="GoToRedLightState" StateName="VisualStateRedLight"/> </i:EventTrigger> </i:Interaction.Triggers> </Button> <Button x:Name="ButtonYellowLight" Content="Yellow Light"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <ei:GoToStateAction x:Name="GoToYellowLightState" StateName="VisualStateYellowLight"/> </i:EventTrigger> </i:Interaction.Triggers> </Button> <Button x:Name="ButtonGreenLight" Content="Green Light"> <i:Interaction.Triggers> <i:EventTrigger EventName="Click"> <ei:GoToStateAction x:Name="GoToGreenLightState" StateName="VisualStateGreenLight"/> </i:EventTrigger> </i:Interaction.Triggers> </Button> </StackPanel> </Grid> </Window>
Notice there are additional dependencies added that come from System.Windows.Interactivity.dll:
- xmlns:i=”http://schemas.microsoft.com/expression/2010/interactivity”
Mli>xmlns:ei=”http://schemas.microsoft.com/expression/2010/interactions”
There is a lot more to learn. We didn’t even touch Transition or Easing methods. We didn’t discuss how to hook this up into a full application, or possible an MVVM application.