Silverlight ProgressBar Control

ProgressBar seemed to be the easiest control to start with as it does not have much visual complexity and even the OM it exposes is very simple. Only OM it exposes are Height/Width properties that are common for all controls and Maximum/Minimum/Value properties.

It would be useful to download and install following things...

  1. Silverlight Alpha 1.1 runtime
  2. Visual Studio Orcas
  3. Silverlight tools extension for VS Orcas
  4. Expression Blend May Preview

To create new control. Go to Visual studio and click "New Project", you should see Silverlight option. I used Silverlight Class Library. Deleted the Class that gets created by default. Right Click on project and Click on Add New Item and select Silverlight User Control.

So now after naming appropriately, you have ProgressBar.Xaml and ProgressBar.Xaml.cs in the project.

One of my favorite feature in this tools release is that you can right click on XAML file and say open in Expression Blend.

 This is a very good feature and highlights the developer design workflow. This way all your visual assets can be edited by designers and code can be worked on by developer. Since VS as well as Expression can open projects created by each other, it allows you to visually design the looks of the control. This is one of the main reasons why you should keep the visuals in the XAML instead of creating them in code because ones created in code are difficult to manipulate by designers.

Once I open the XAML file, I changed the looks of the progress bar, which basically consists of three elements....rootCanvas, rectangle that shows the track of ProgressBar and rectangle that shows the fill of ProgressBar. I picked the colors using my limited sense of color and design but the whole point is somebody who has better sense could make it look like much beautiful.

This looks something like this.

Now I can save in Sparkle and it updates the XAML in VS too. Xaml looks like this...

 <Canvas
    xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
    Width="480" Height="48" x:Name="rootCanvas">
  <Rectangle RadiusX="5" RadiusY="5" x:Name="rectProgressBarTrack" Width="472" Height="32" Canvas.Left="4" Canvas.Top="8">
    <Rectangle.Fill>
      <LinearGradientBrush EndPoint="0.5,0" StartPoint="0.5,1">
        <GradientStop Color="#FF7B7979" Offset="0"/>
        <GradientStop Color="#FF797676" Offset="1"/>
        <GradientStop Color="#FFBFBCBC" Offset="0.495"/>
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
  <Rectangle RadiusX="5" RadiusY="5" Width="172" Height="32" Canvas.Left="4" Canvas.Top="8" x:Name="rectProgressBarFill" >
    <Rectangle.Fill>
      <LinearGradientBrush EndPoint="0.5,0" StartPoint="0.5,1">
        <GradientStop Color="#FE7BC3E5" Offset="0"/>
        <GradientStop Color="#FE7DC6EC" Offset="0.995"/>
        <GradientStop Color="#FE0089E1" Offset="0.529"/>
      </LinearGradientBrush>
    </Rectangle.Fill>
  </Rectangle>
</Canvas>

This XAML defines the "look" of the control. Now Implement the class that defines the behavior and APIs for progressbar control.

By default, VS embeds this XAML as a resource in the assembly. so to use it during runtime we need to do following steps...

  1. Get handle to the assembly
  2. Get the resource from within this assembly as a stream
  3. Convert Stream to String
  4. Use Control's InitializeFromXaml to instantiate the visual tree

 

  public ProgressBar()
        {
            //get executing assembly since the XAML that defines the look of the control
            //is embedded in the assembly. 
            Assembly ProgressBarAssembly = Assembly.GetExecutingAssembly();
            //read the stream for the resource
            System.IO.StreamReader xamlstream = new System.IO.StreamReader((ProgressBarAssembly.GetManifestResourceStream("ProgressBar.ProgressBar.xaml")));
            //convert stream in string
            _progressBarLook = xamlstream.ReadToEnd();
            //call initialize from XAML to create the visual tree. 
            _progressBarRoot = InitializeFromXaml(_progressBarLook) as Canvas;
            //get handles other element in the tree so that they can be manipulated for layout etc.
            _progressBarFillRectangle = _progressBarRoot.FindName("rectProgressBarFill") as Rectangle;
            _progressBarTrackRectangle = _progressBarRoot.FindName("rectProgressBarTrack") as Rectangle;
            //loaded event handler so that Height/Width set in the markup get processed. 
            this.Loaded += new EventHandler(ProgressBar_Loaded);
        }

Apart from that only progressbar specific OM that needs to be implemented is Minimum, Maximum and Value property.

 

 public double Minimum
        {
            get { return _minValue; }
            set { _minValue = value; }
        }

        public double Maximum
        {
            get { return _maxValue; }
            set { _maxValue = value; }
        }

        public double Value
        {
            get { return _value; }
            set
            {
                if (value <= Maximum && value >= Minimum)
                {
                    _value = value;
                    _progressBarFillRectangle.Width = ((_progressBarTrackRectangle.Width / (_maxValue - _minValue)) * (_value - _minValue));
                }
            }
        }

 

To use the control....

  1. Create New project of type "Silverlight Project"
  2. Add a reference to the ProgressBar project.
  3. Use the control in the XAML.

 

 <Canvas x:Name="rootCanvas"
        xmlns="https://schemas.microsoft.com/client/2007"
        xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
        Loaded="Page_Loaded"
        x:Class="ControlApplication.ControlUse;assembly=ClientBin/ControlApplication.dll"
        xmlns:Custom1="clr-namespace:SPFControls;assembly=ClientBin/ProgressBar.dll"
        Width="1000"
        Height="1000"
        Background="White">
   <Custom1:ProgressBar Name="progressBar" Canvas.Top ="50" Minimum ="0" Maximum="10" Height="40" Width="500" Canvas.Left ="100" Value="55"/>
</Canvas>

Full code for the progressbar looks like this...