Silverlight Tip of the Day #21 – How to work with Shapes, Brushes and Gradients

Shapes, gradients and brushes provide the user with a lot of power to make custom controls that look beautiful. For example, gradients can be made to look like shadows or lighting for stunning visual effects. For this demo, we are going to make the beginnings of what could end up being a clock, or taken further, a gauge. The screen shot below is what we will be achieving in this tutorial.

image

Before we make this clock, let’s review the properties that will make these controls.

Shapes Elements

Silverlight supports what is called vector graphics by providing the following basic shapes:

  • Ellipse – Describes an oval or circle.
  • Rectangle – Describes a rectangle or a square (can have rounded corners).
  • Line – Describes a line that connects two points.
  • Polygon – Describes a closed shape with an arbitrary number of sides.
  • Polyline – Descries a series of connected lines that may or may not form a closed shape.
  • Path – Describes complex shapes that include curves and arcs.

Color

Color can be specified in one of the following formats:

  • Its name such as “Red”, “Blue”, “Black”, etc.
  • A 6 digit RGB (red, green, blue) notation #rrggbb where rr, gg and bb are the two digit hexadecimal value that describes the amount of color for red, green and blue respectively. Example: #FF0000 would be a bright red color.
  • A 8 digit ARGB (alpha, red, green, blue) notation with two extra values that describe the alpha value (opacity) of the color. For example, #FFFF0000 would be bright red with no opacity.

Fill & Fill

Shapes consist of two parts, the outer outline (border) and the inner part. The color of these parts are controlled through the Stroke and Fill properties. Some shapes such as a Line only have a stroke. Specifying a Fill for a line would have no affect.

image

Brushes

Using <Ellipse.Fill> we can fill this ellipse using one of the following brush options:

  • A linear gradient brush – Paints a gradient along a line. The line is diagonal and stretches from the upper left to the lower right corner by default. The properties StartPoint and EndPoint can change these positions.
  • A Image brush – Paints with an image.
  • A radial gradient brush – Paints a gradient along a circle. By default, the circle is centered on the area being painted.
  • A solid color brush – Paints an area with a solid color.
  • A video brush – Paints an area with live streaming video.

Here is an example of each:

image

As appears in source code:

 <MediaElement Canvas.Top="300" x:Name="MyMedia" Source="MyVideo.wmv" Width="300" Height="300" />
  
 <Ellipse Canvas.Top="20" Canvas.Left="5" Width="100" Height="100" StrokeThickness="2">
     <Ellipse.Fill>
         <LinearGradientBrush
         StartPoint='0.1,0.06'
         EndPoint='0.5,0.6'>
             <GradientStop Color='#FFFFFFFF' Offset='0'/>
             <GradientStop Color='#FF000000' Offset='1'/>
         </LinearGradientBrush>
     </Ellipse.Fill>
 </Ellipse>
  
 <Ellipse  Canvas.Top="20" Canvas.Left="105" Width="100" Height="100" StrokeThickness="2">
     <Ellipse.Fill>
         <ImageBrush ImageSource="clock.png" Stretch="Uniform"></ImageBrush>
     </Ellipse.Fill>
 </Ellipse>
  
 <Ellipse Canvas.Top="20" Canvas.Left="205" Width="100" Height="100" StrokeThickness="2">
     <Ellipse.Fill>
         <RadialGradientBrush>
             <GradientStop Color="Yellow" Offset="0.0" />
             <GradientStop Color="Red" Offset="1.0" />
         </RadialGradientBrush>
     </Ellipse.Fill>
 </Ellipse>
  
 <Ellipse Canvas.Top="20" Canvas.Left="305" Width="100" Height="100" StrokeThickness="2">
     <Ellipse.Fill>
         <SolidColorBrush Color="Blue"/>
     </Ellipse.Fill>
 </Ellipse>
  
 <Ellipse Canvas.Top="20" Canvas.Left="405" Width="100" Height="100" StrokeThickness="2">
     <Ellipse.Fill>
         <VideoBrush SourceName="MyMedia" />
     </Ellipse.Fill>
 </Ellipse>

For the Video brush, make certain the video file is placed in your web sites ClientBin folder.

On to making the clock! We start with a simple ellipse in a <Canvas> object setting it’s Width and Height to 200. For the Fill property, we will apply the LinearGradientBrush

 <Grid x:Name="LayoutRoot" Background="Gray">
     <Canvas x:Name="Clock">
         <Ellipse Canvas.Top="150" Canvas.Left="5" Width="200" Height="200" StrokeThickness="2">
             <Ellipse.Fill>
                 <LinearGradientBrush StartPoint='0.1,0.06' EndPoint='0.5,0.6'>
                     <GradientStop Color='#FFFFFFFF' Offset='0'/>
                     <GradientStop Color='#FF000000' Offset='1'/>
                 </LinearGradientBrush>
             </Ellipse.Fill>
         </Ellipse>
     </Canvas>
 </Grid>

 

This code will generate the following circle:

image

Let’s add another small circle in the middle plus 2 sets of 3 red lines to make the the hour and minute hands for the clock.

             <Line X1="100"  X2="25"  Y1="246" Y2="247" Stroke="Red" StrokeThickness="1" />
             <Line X1="100"  X2="25"  Y1="247" Y2="247" Stroke="Red" StrokeThickness="1" />
             <Line X1="100"  X2="25"  Y1="248" Y2="247" Stroke="Red" StrokeThickness="1" />
  
             <Line X1="106"  X2="60"  Y1="246" Y2="290" Stroke="Red" StrokeThickness="1" />
             <Line X1="106"  X2="60"  Y1="247" Y2="290" Stroke="Red" StrokeThickness="1" />
             <Line X1="106"  X2="60"  Y1="248" Y2="290" Stroke="Red" StrokeThickness="1" />
  
             <Ellipse Width="15" Height="15" Canvas.Left="100" Canvas.Top="240">
                 <Ellipse.Fill>
                     <LinearGradientBrush
                         StartPoint='0.1,0.06'
                         EndPoint='0.5,0.6'>
                         <GradientStop Color='#FFFFFFFF' Offset='0'/>
                         <GradientStop Color='#FF000000' Offset='1'/>
                     </LinearGradientBrush>
                 </Ellipse.Fill>
             </Ellipse>

image

Finally, for the numbers we will programmatically generate and add them as Textblocks. We do this by calculating the X & Y location along a circle with a radius of 85 pixels. Each number is separated by 30 degrees. We start at 1:00 which is located at an angle of 300 degrees.

    1: private void AddNumbers()
    2: {
    3:     double angle = 300;
    4:     for (int i = 1; i < 13; i++)
    5:     {
    6:         TextBlock tb = new TextBlock();
    7:         tb.Foreground = new SolidColorBrush(Colors.White);
    8:         tb.Text = i.ToString();
    9:  
   10:         double radians = angle * (Math.PI / 180);
   11:         double radius = 85;
   12:         int x = (int)(radius * Math.Cos(radians));
   13:         int y = (int)(radius * Math.Sin(radians));
   14:         tb.SetValue(Canvas.LeftProperty, (double) x+97);
   15:         tb.SetValue(Canvas.TopProperty, (double) y+239);
   16:  
   17:         angle += 30;
   18:         Clock.Children.Add(tb);
   19:     }
   20: }

Here is our final result:

image

Thank you,

--Mike Snow

 Subscribe in a reader

Comments