In this tutorial, I will show you how to create a WPF image viewer in Expression Blend. The application will (hopefully) look like the following image once you are through:.
The application will have some basic functionality allowing the user to pan and zoom an image. Zooming will be achieved by scrolling the mouse wheel. The buttons in the application are custom buttons, and you'll need to make use of the VS2008 Image Library.
Let's start off by designing the UI of the application. Start Expression Blend and create a new WPF application project named 'Image Viewer'. Ensure that the language is set to Visual Basic in the Language combo box.
- Select the Window element in Objects and Timeline. Select Background in the Brushes section of the Properties panel, and set the background to a gradient brush. Set the first gradient stop to white, and the second to a light shade of grey.
- Select the canvas tool from the toolbox. Draw out a canvas in the
- In the Layout section of the Properties panel, set the top, left, and right margins of the canvas to 15, and the bottom margin to 60.
- In the Appearance section of the Properties panel, click on the Advanced Properties button. Check the ClipToBounds checkbox.
- Rename the canvas to '
- Select the Assets panel and type the word 'content' in the search box. You will be presented with several tools. Select the
- Draw out a
ImgCanvas. Using the resize handles, if necessary, set it to fit the canvas edge-to-edge. (Turn on snapping to snaplines so that the edges of the
ContentControl snap onto those of the canvas.)
Snapping to snaplines button
ContentControl to '
ImgContentCtrl' and in the Common Properties section of the Properties panel, delete the text in the
- In the Layout section, set the
Top properties of
ImgContentCtrl to zero.
- Select the Grid tool from the toolbox, and draw out a grid in
ImgContentCtrl. Set the grid's edges to fit exactly with those of the
- Rename the grid to '
- Type the word 'image' in the search box of the Assets panel. With
ImgGrid still selected, double click on the
Image tool to add an image object to
- Right click the
Image object in Objects and Timeline and select Auto Size > Fill from the context menu.
- Rename the
Image object to '
- Type the word 'thumb' in the search box of the Assets panel. You are presented with several tools. Double click on the
Thumb tool to add it to
ImgGrid has to be the active content control. The active content control has a blue border.)
- Rename the thumb control to '
ImgThumb'. Right click
ImgThumb and select Auto Size > Fill from the context menu.
- In the Appearance section of the Properties panel, set the opacity of
ImgThumb to zero.
The design work is nearly complete, but we need to add some button controls. We shall create two custom buttons, one for showing an Open File dialog, the other for making the image viewable in full after a zoom action. I prefer designing my custom buttons in Expression design, but in this case, to make work easier, we shall make use of some of the images in the VS2008 Image Library. I will specifically make use of some of the images found in the path "C:\Program Files\Microsoft Visual Studio 9.0\Common7\VS2008ImageLibrary\1033\VS2008ImageLibrary\Objects\png_format\WinVista".
Let's design the custom buttons:
LayoutRoot in Objects and Timeline to make it the active control.
- Select the
Grid tool from the toolbox and draw a grid close to the bottom-left edge of the
LayoutRoot. I have set my grid to a width of 40 and a height of 36. The top and right margins are zero, and the left margin is 34, while the bottom margin is 8.
- With the new grid still selected, type 'image' in the search box of the Assets panel. Double click on the Image tool to add an image object to the new grid.
- In the Common Properties section of the Properties panel, select the button with ellipses right next to the Source property combo box. This opens the Add Existing Item dialog box. Navigate and open the file named Folder_Open in the path "C:\Program Files\Microsoft Visual Studio 9.0\Common7\VS2008ImageLibrary\1033\VS2008ImageLibrary\Objects\png_format\WinVista".
- Right click the new grid in Objects and Timeline and select Make Into Control from the context menu. In the Make Into Control dialog that appears, select the button control (it is the default) and click on OK.
- The custom button's template will be opened when you click on OK. Select the
ContentPresenter in Objects and Timeline. Delete the text in the
Content property in the Common Properties section of the Properties panel.
Next we shall animate the custom button so that it increases slightly in size during
- Click on the New button in Objects and Timeline (the New button is the one with a plus sign).
- Click on OK in the resulting dialog to create a new storyboard with the default name
- Select the grid element in Objects and Timeline then drag the playhead to 5 milliseconds.
- Hold down Shift + Alt, and using the grid element's resize handles, slightly increase the size of the grid by dragging outwards.
- In the Objects and Timeline panel, click on the dropdown arrow next to the New button and select Duplicate from the context menu. A duplicate of
Storyboard_Copy1, is created and opened.
- In Objects and Timeline, click on the dropdown arrow next to the New button and select Reverse from the context menu.
- In Objects and Timeline, click on the Close Storyboard button.
- Select the Triggers panel and then select the
IsMouseOver property trigger.
- Click on the Add new action button in the Actions when activating section.
Storyboard1 is set to begin as the default action.
- Click on the Add new action button in the Action when deactivating section.
Storyboard1 is set to begin as the default action. Click on the dropdown arrow of the first combo box and select Storyboard_Copy1.
- Click on the Scope Up button in Objects and Timeline to exit the edit-template mode.
- Rename the button to '
OpenButton still selected, copy-paste a new button onto the Window element. The new button is pasted on top of the first button. Using the right arrow key, nudge it to the right of the first button.
- Rename the new button to '
- Right click
BestFitButton and select Edit Template > Edit a Copy from the context menu. Click on OK in the resulting dialog to open the button's template.
- In Objects and Timeline, select the image object and click on the ellipses button next to the
Source property combo box in the Common Properties section of the Properties panel.
- In the Add Existing Item dialog, navigate to the folder "C:\Program Files\Microsoft Visual Studio 9.0\Common7\VS2008ImageLibrary\1033\VS2008ImageLibrary\Objects\png_format\WinVista" and open the file named "generic_picture".
- Click on the Scope Up button to exit edit-template mode.
- In the Common Properties section of the Properties panel, set the
Tooltip property of
OpenButton to 'Open File' and that of
BestFitButton to 'Best Fit'.
The design work is finally complete. Coding is next, so save your work if you haven't been doing so.
Next, we shall add code to enable the user to open an image file, zoom-in and out on an image at the cursor location, pan the image, and restore the image to a suitable view after a zoom action.
- Select the Project panel and expand MainWindow.xaml. Double click on MainWindow.xaml.vb to open it in Blend's code editor.
- Add the following code:
Private myScale as New ScaleTransform
Public Sub New()
ImgContentCtrl.RenderTransform = myScale
- Next, we'll add code to enable panning. Switch back to the design window and select
ImgThumb in the Objects and Timeline panel.
- Click on the Events button in the Properties panel to display the
Thumb control's events.
- Type 'ImgThumb_DragDelta' in the
DragDelta event textbox and press Enter.
DragDelta event handler, type in the following code:
Dim left as Double = Canvas.GetLeft(ImgContentCtrl)
Dim top as Double = Canvas.GetTop(ImgContentCtrl)
Canvas.SetLeft(ImgContentCtrl, (left + e.HorizontalChange))
Canvas.SetTop(ImgContentCtrl, (top + e.VerticalChange))
- The previous code caters for panning actions, so let's add code for zooming. Switch back to the designer window and scroll down
ImgThumb's events for the
MouseWheel event. Type 'ImgThumb_MouseWheel' in the
MouseWheel event textbox and press Enter.
- Type in the following code in
MouseWheel event handler:
Dim deltaValue as Integer
deltaValue = e.Delta
myScale.CenterX = e.GetPosition(ImgContentCtrl).X
myScale.CenterY = e.GetPosition(ImgContentCtrl).Y
If deltaValue > 0 Then
If myScale.ScaleX < 5 Then
myScale.ScaleX += 0.1
myScale.ScaleY += 0.1
If myScale.ScaleX > 0.8 Then
myScale.ScaleX -= 0.1
myScale.ScaleY -= 0.1
That does it for zooming and panning. Next, we'll add code for opening an image file and restoring the image to full view after zooming or panning.
- Switch back to the designer window and select
OpenButton in Objects and Timeline.
- In the Properties panel, look for the
Click event (it's at the top, so scroll up) and type 'OpenButton_Click' in the
Click event textbox. Press Enter.
- Type the following code just before the class declaration:
Click event handler, type in the following code:
Dim OpenDialog as New OpenFileDialog
.Filter = "Image Files (*.jpeg)|*.jpg|All Files (*.*)|*.*"
.Title = "Open Image File"
If OpenDialog.FileName <> String.Empty Then
Dim newImage As New BitmapImage()
newImage.UriSource New Uri(OpenDialog.FileName, UriKind.RelativeOrAbsolute)
ImgObject.Source = newImage
- Switch back to the design window and select
BestFitButton. Type 'BestFitButton_Click' in the
Click event textbox of the Properties panel and press Enter.
- Type in the following code in
Click event handler:
BestFit() method, that is called in both the
Click event handlers, sets the image to a suitable fit in the canvas so that it is fully viewable after a zoom or scroll action. Type in the following code in Blend's code editor:
Private Sub BestFit()
myScale.ScaleX = 1
myScale.ScaleY = 1
You can now run the project and open an image file. Try zooming and panning. If there are any errors, check your code. Notice that when you maximize the window, the image doesn't stay centered. To remedy this, stop the project if it's still running. Right-click
ImgCanvas and select GroupInto > ViewBox. Run the project again, and once you've opened an image file, maximize the window.
The image viewer application doesn't have scrollbars, but you can implement them by grouping
ImgCanvas in a
ScrollViewer and increasing
ImgCanvas' size as you zoom-in. You'll have to play around with the code to get it working perfectly, but I believe the current implementation is suitable. I hope the article was helpful. Thanks for reading.
- 21 July, 2010: Initial post.