WPF Image Viewer






4.91/5 (20 votes)
Learn how to create a WPF image viewer in Expression Blend.
Introduction
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:.
Background
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.
Design
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
LayoutRoot
. - 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 '
ImgCanvas
'. - Select the Assets panel and type the word 'content' in the search box. You will be presented with several tools. Select the
ContentControl
tool. - Draw out a
ContentControl
inImgCanvas
. 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 theContentControl
snap onto those of the canvas.) - Rename
ContentControl
to 'ImgContentCtrl
' and in the Common Properties section of the Properties panel, delete the text in theContent
property. - In the Layout section, set the
Left
andTop
properties ofImgContentCtrl
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 theContentControl
. - Rename the grid to '
ImgGrid
'. - Type the word 'image' in the search box of the Assets panel. With
ImgGrid
still selected, double click on theImage
tool to add an image object toImgGrid
. - Right click the
Image
object in Objects and Timeline and select Auto Size > Fill from the context menu. - Rename the
Image
object to 'ImgObject
'. - 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 toImgGrid
. (ImgGrid
has to be the active content control. The active content control has a blue border.) - Rename the thumb control to '
ImgThumb
'. Right clickImgThumb
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:
- Select
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 theLayoutRoot
. 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 theContent
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 Mouse_Over
events.
- 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
Storyboard1
. - 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
Storyboard1
,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
'. - With
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 '
BestFitButton
'. - 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 ofOpenButton
to 'Open File' and that ofBestFitButton
to 'Best Fit'.
The design work is finally complete. Coding is next, so save your work if you haven't been doing so.
Coding
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:
- 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. - In
ImgThumb
'sDragDelta
event handler, type in the following code: - 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 theMouseWheel
event. Type 'ImgThumb_MouseWheel' in theMouseWheel
event textbox and press Enter. - Type in the following code in
ImgThumb
'sMouseWheel
event handler:
' Create a ScaleTransform object
Private myScale as New ScaleTransform
Public Sub New()
Me.InitializeComponent()
' Set the ContentControl's RenderTransform property
ImgContentCtrl.RenderTransform = myScale
End Sub
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))
' Variable for holding the mouse's delta value.
Dim deltaValue as Integer
deltaValue = e.Delta
' Set the center point of the ScaleTransform object
' to the cursor location.
myScale.CenterX = e.GetPosition(ImgContentCtrl).X
myScale.CenterY = e.GetPosition(ImgContentCtrl).Y
' Zoom in when the user scrolls the mouse wheel up
' and vice versa.
If deltaValue > 0 Then
' Limit zoom-in to 500%
If myScale.ScaleX < 5 Then
' Zoom-in in 10% increments
myScale.ScaleX += 0.1
myScale.ScaleY += 0.1
End If
' When mouse wheel is scrolled down...
Else
' Limit zoom-out to 80%
If myScale.ScaleX > 0.8 Then
' Zoom-out by 10%
myScale.ScaleX -= 0.1
myScale.ScaleY -= 0.1
End If
End If
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 theClick
event textbox. Press Enter. - Type the following code just before the class declaration:
- In
OpenButton
'sClick
event handler, type in the following code: - Switch back to the design window and select
BestFitButton
. Type 'BestFitButton_Click' in theClick
event textbox of the Properties panel and press Enter. - Type in the following code in
BestFitButton
'sClick
event handler: - The
BestFit()
method, that is called in both theBestFitButton
andOpenButton
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:
Imports Microsoft.Win32
Dim OpenDialog as New OpenFileDialog
With OpenDialog
.Filter = "Image Files (*.jpeg)|*.jpg|All Files (*.*)|*.*"
.Title = "Open Image File"
End With
OpenDialog.ShowDialog()
If OpenDialog.FileName <> String.Empty Then
Dim newImage As New BitmapImage()
newImage.BeginInit()
newImage.UriSource New Uri(OpenDialog.FileName, UriKind.RelativeOrAbsolute)
newImage.EndInit()
' Load image file into Image Control
ImgObject.Source = newImage
End If
' Set the view of the ContentControl to a
' suitable scale and centered.
BestFit()
BestFit()
Private Sub BestFit()
' Set the scale of the ContentControl
' to 100%.
myScale.ScaleX = 1
myScale.ScaleY = 1
' Set the position of the ContentControl
' so that the image is centered.
Canvas.SetLeft(ImgContentCtrl, 0)
Canvas.SetTop(ImgContentCtrl, 0)
End Sub
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.
Conclusion
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.
History
- 21 July, 2010: Initial post.