Windows Phone 7 Custom ProgressBar

What appeared to be straight forward proved to be a bit more difficult than I anticipated. I wanted to create a customized ProgressBar for the Windows Phone. The ProgressBar should take any image as input and Fill the image depending on the progress indicated by the Value property.

In pictures:
image imageimageimage

So I create a class deriving from ProgressBar:

using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;

namespace CustomControls
{
    [TemplatePart(Name="CLIPRECTANGLE", Type=typeof(RectangleGeometry))]
    public class ImageProgressBar : ProgressBar
    {
        public ImageProgressBar()
        {
            this.DefaultStyleKey = typeof(ImageProgressBar);
        }

        public ImageSource Source
        {
            get { return (ImageSource)GetValue(SourceProperty); }
            set { SetValue(SourceProperty, value); }
        }

        public static readonly DependencyProperty SourceProperty =
            DependencyProperty.Register("Source", typeof(ImageSource), typeof(ImageProgressBar), new PropertyMetadata(null));

        public Brush Fill
        {
            get { return (Brush)GetValue(FillProperty); }
            set { SetValue(FillProperty, value); }
        }

        public static readonly DependencyProperty FillProperty =
            DependencyProperty.Register("Fill", typeof(Brush), typeof(ImageProgressBar), new PropertyMetadata(null));

        private RectangleGeometry _clip;

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            _clip = this.GetTemplateChild("CLIPRECTANGLE") as RectangleGeometry;
            this.ValueChanged += ImageProgressBar_ValueChanged;
            this.SizeChanged += ImageProgressBar_SizeChanged;
        }

        void ImageProgressBar_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            UpdateClip();
        }

        void ImageProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
        {
            UpdateClip();
        }

        private void UpdateClip()
        {
            if (_clip != null)
            {
                _clip.Rect = new Rect(0, 0, this.ActualWidth, this.ActualHeight * ((this.Value - this.Minimum) / (this.Maximum - this.Minimum)));
            }
        }
    }
}

The Source property can be used to point to the image. The Fill property points to a brush that should fill the image. The _clip points to a RectangleGeometry in the template that has to cut off a part of the fill according to the progress.

The UpdateClip adjusts the Rectangle based on the size of the progress bar and the progress indicated by the Value property.

Next up; the template:

&lt;ResourceDictionary  class="wlWriterEditableSmartContent"><pre>
[sourcecode language="xml" htmlscript="false"]
&lt;my:ImageProgressBar Width=&amp;quot;100&amp;quot;
                     Height=&amp;quot;100&amp;quot;
                     Fill=&amp;quot;Red&amp;quot;
                     Source=&amp;quot;ProgressBar.png&amp;quot;
                     Minimum=&amp;quot;100&amp;quot;
                     Maximum=&amp;quot;200&amp;quot;
                     Value=&amp;quot;{Binding ElementName=slider1, Path=Value, Mode=TwoWay}&amp;quot; /&gt;
&lt;Slider Margin=&amp;quot;0&amp;quot;
        Name=&amp;quot;slider1&amp;quot;
        VerticalAlignment=&amp;quot;Top&amp;quot;
        Minimum=&amp;quot;100&amp;quot;
        Maximum=&amp;quot;200&amp;quot;
        Value=&amp;quot;125&amp;quot; /&gt;

I added a slider to see the progress on the Phone.

Download the code here