Title: Use WPF to make a download button in C#
This example uses WPF to make a download button. The following XAML code shows how the program builds the button.
<Window x:Class="howto_download_button.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="107" Width="140" Loaded="Window_Loaded"
WindowStyle="ToolWindow">
<Grid Background="Transparent" Name="grdMain">
<!-- The button's background -->
<Ellipse Margin="5" StrokeThickness="5">
<Ellipse.Fill>
<RadialGradientBrush>
<GradientStop Color="LightGreen" Offset="0"/>
<GradientStop Color="#FF00C000" Offset="1"/>
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
<!-- Text -->
<TextBlock FontFamily="Arial Rounded MT" FontSize="20"
FontWeight="Bold" Foreground="Black"
Margin="10" HorizontalAlignment="Center"
VerticalAlignment="Center"
TextWrapping="Wrap">
Download
</TextBlock>
<!-- Highlight -->
<Ellipse VerticalAlignment="Top"
Height="30" Margin="20,8,20,0"
Fill="White" Opacity="0.5">
</Ellipse>
</Grid>
</Window>
The program's window contains a Grid control that contains two Ellipses and a TextBlock. The first Ellipse defines the button's background. It is filled with a RadialGradientBrush that shades from LightBlue in the center to a darker blue around the edges.
The TextBlock displays the text "Download."
The second Ellipse is white and sits on top of the other controls. It's positioned so it starts a bit below the top of the button, extends vertically to the middle of the button, and doesn't cover the entire width of the button. It's Opacity is 0.5 so it is 50% opaque and the other controls show through.
The result is pretty good considering the button only uses three controls. (Of course it took a lot of fiddling to make the result match the Twitter button reasonably well.)
When it starts, the program uses the following code to save an image of the Grid control into a png file. (This is typical code for saving a control's image.)
// Save an image of the grid.
private void Window_Loaded(object sender, RoutedEventArgs e)
{
// Render the grid.
RenderTargetBitmap bm = new RenderTargetBitmap(
(int)grdMain.ActualWidth, (int)grdMain.ActualHeight,
96, 96, PixelFormats.Default);
bm.Render(grdMain);
// Save the result into a file.
using (var fileStream = new FileStream("Download.png",
FileMode.Create))
{
BitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(bm));
encoder.Save(fileStream);
}
}
The program creates a RenderTargetBitmap with the same size as the Grid, using 96 pixels per inch resolution, and the default pixel format. It then calls the Grid's Render method to make it draw itself (and its contents) onto the RenderTargetBitmap.
Next the program creates a FileStream representing the file that should contain the image. It makes a PngBitmapEncoder to save the image in the png format.
The program then calls the encoder's Frames.Add method to add a new frame to it. It passes the method a new BitmapFrame generated by the class's Create method, passing that method the RenderTargetBitmap.
Finally, after it has created the new frame, the program calls the encoder's Save method.
(If this all seems a annoyingly convoluted, I agree. This is one of my biggest complaints with WPF. Even though .NET programmers have been working with images and saving them into files for years, WPF makes this so much harder. It's like the WPF designers had never saved an image before. In fact, just about everything is harder. It makes me wonder if the developers who designed WPF had ever programmed in .NET.)
Download the example to experiment with it and to see additional details.
|