LA.NET [EN]

Jul 25

Silverlight: building a simple progress bar

Posted in Silverlight      Comments Off on Silverlight: building a simple progress bar

When you”re developing a Silverlight application, you”ll surelly be in a situation where you need to download stuff before starting your app. In these cases, you should play nice with the user and give them some indications regarding what”s going on. The most common thing to do in these scenarios is to show a progress bar.

Building a progress bar in silverlight is simple and I”ll try to show you how you can build one quickly. In my example, I”ve built a simple UserControl that you can reuse to show the progress of a task. Here”s what I”ve got in the XAML file:

<Canvas xmlns=”http://schemas.microsoft.com/client/2007″
xmlns:x=”http://schemas.microsoft.com/winfx/2006/xaml”
Width=”300″
Height=”22″>
<Rectangle Stroke=”#FF000000″ StrokeThickness=”1″ x:Name=”border”
Canvas.ZIndex=”2″
Width=”298″ Height=”22″ Canvas.Left=”0″ Canvas.Top=”0″ />
<Rectangle Stroke=”#FF000000″ StrokeThickness=”0″ x:Name=”fill”
Width=”298″ Height=”22″ Canvas.Left=”0″ Canvas.Top=”0″>
<Rectangle.Fill>
<LinearGradientBrush EndPoint=”1,0.5″ StartPoint=”0,0.5″>
<GradientStop Color=”#FFDD9090″ Offset=”0″/>
<GradientStop Color=”#FFFFFFFF” Offset=”1″/>
</LinearGradientBrush>
</Rectangle.Fill>
</Rectangle>
<TextBlock x:Name=”info” Width=”50″ Height=”19″ Canvas.Left=”125″ Canvas.Top=”3″ FontSize=”9″ Text=”100%” TextWrapping=”Wrap”/>
</Canvas>

Now, the code:

namespace Silverlight.Controls
{
  public class ProgressBar : Control
  {
    private Canvas _root;

    public ProgressBar()
    {
          System.IO.Stream s = this.GetType().Assembly.GetManifestResourceStream(“SilverlightProgressBar.ProgressBar.xaml”);
         _root = (Canvas)this.InitializeFromXaml(new System.IO.StreamReader(s).ReadToEnd());

         UpdateInfoPos();
         UpdateUI(0);
   }

   public double CtlHeight
   {
       get { return _root.Height; }
       set
      {
       _root.Height = value;
       ProgressRect.Height = _root.Height = ProgressRectBorder.Height ;
      }
  }

   public double CtlWidth
   {
      get { return _root.Width; }
      set
      {
           double currentPercentage = Percentage;
           _root.Width = value;
           ProgressRectBorder.Width = _root.Width = ProgressRect.Width = value;
           UpdateInfoPos();
           UpdateUI(currentPercentage);
      }
   }

   public double Percentage
   {
        get { return (ProgressRect.Width / _root.Width) * 100.0; }
        set {  UpdateUI(value > 100 ? 100 : value); }
   }

   private void UpdateInfoPos()
   {
        double leftPos = (_root.Width – Info.ActualWidth) / 2;
        Info.SetValue(Canvas.LeftProperty, leftPos);
   }

   private void UpdateUI(double currentPercentage)
   {
     ProgressRect.Width = (currentPercentage * _root.Width) / 100.0;
     Info.Text = string.Concat(currentPercentage, “%”);
   }

   private Rectangle ProgressRect
   {
     get { return (Rectangle)_root.FindName(“fill”); }
   }

   private Rectangle ProgressRectBorder
   {
      get { return (Rectangle)_root.FindName(“border”); }
   }

   private TextBlock Info
   {
      get { return (TextBlock)_root.FindName(“info”); }
    }
  }
}

Nothing too fancy as you can see, but there are still some observations that need to be made:

  • I”ve added CtlWidth and CtlHeight because newing the Witdh and Height properties doesn”t work from XAML, ie, redefining the width and height properties only lets you define the width/heighr from your codebehind file. If you try to set those properties from your XAML file,it won”t work;
  • I”ve added private fields to simplify access to the named objects defined on the XAML file;
  • The current percentage is calculated by comparing the width of the rectangle against the width of the canvas that hosts it.

As you can see,the code for a progress bar is really simple and you only need to pay attention to some details (like the Width/Height problem i”ve mentioned).