The example Make a three-dimensional cube that displays different pictures on each side with WPF, XAML, and C# that uses six different images for its sides. This post explains how that program does two other useful things: responding to menu events and saving images in a PNG file.
Responding to WPF Events
There are two ways you can make C# code respond to WPF object events. First, you can use AddHandler. This works just as it does in Windows forms programming. It requires some extra code so it’s not terribly convenient but it is easy.
The second way to make C# code respond to WPF object events is to put the name of the event handler in the XAML code. The following code shows how the example program indicates that the MenuItem named mnuView111 uses the btnView_Click method as the event handler for its Click event.
This isn’t too hard and Visual Studio’s IntelliSense will even help you select an event handler or create a new one. The major drawback to this method is that Expression Blend cannot run the program without the C# code behind. If you try to run the program without the C# code, the program says it can’t find a definition for the btnView_Click event handler. This makes it hard to let different people work on the user interface and the C# code separately, a major goal of WPF.
Still, this isn’t too bug a restriction. For testing purposes you can make stubs of the routines so the interface designer can run the program without the real C# code.
Saving an image isn’t too hard once you know the arcane steps. This example uses the following code to save an image of the three-dimensional cube.
// Save the current image.
private void mnuSave_Click(Object sender, RoutedEventArgs e)
// Draw the viewport into a RenderTargetBitmap.
RenderTargetBitmap bm = new RenderTargetBitmap(
96, 96, PixelFormats.Pbgra32);
// Make a PNG encoder.
PngBitmapEncoder encoder = new PngBitmapEncoder();
// Save the file.
using (FileStream fs = new FileStream("Saved.png",
FileMode.Create, FileAccess.Write, FileShare.None))
The code first creates a RenderTargetBitmap on which to draw. It specifies the current actual size of the dockCube control and indicates that the render target should use the Pbgra32 format with 32-bit blue, green, red, and alpha components. The code makes the RenderTargetBitmap render the dockCube control onto itself (yes, that seems backward).
Next the code creates a PngBitmapEncoder and adds a new BitmapFrame to the encoder. It opens the output PNG file and makes the encoder save itself into the file.
(This all seems like a huge step backward to me. It works and the code isn’t too long but it’s amazingly non-intuitive.)
One oddity here is that the Viewport3D object doesn’t have a true background so when you draw it you get a black background. To prevent that, the program puts the Viewport3D inside another control that does have a background, in this case the DockPanel named dockCube.
(For some odd reason, the dockCube control wasn’t drawing its whole background so it was displaying a black stripe at the top. I fixed that by placing it inside yet another DockPanel with a white background. If you figure out why that was happening, let me know.