- bizapp_src.zip
- BizApp
- BizApp.Controls
- BizApp.Services.Server
- BizApp.Services
- BizApp.sln
- BizApp.vsmdi
- BizApp.Web
- BizApp
- LocalTestRun.testrunconfig
- Tests
- BizApp.Services.Test
- Unity Application Block
- Microsoft.Practices.Unity.Configuration.dll
- Microsoft.Practices.Unity.dll
|
// LoadingIndicator.cs
// Author: Jevgenijs Pankovs
// September 21, 2009
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace BizApp.Controls
{
[TemplatePart(Name = "PART_AnimationElement", Type = typeof(FrameworkElement))]
public class LoadingIndicator : Control
{
public static readonly DependencyProperty RadiusProperty =
DependencyProperty.Register("Radius", typeof(int), typeof(LoadingIndicator),
new PropertyMetadata(20, new PropertyChangedCallback(ValueChangedCallback)));
public static readonly DependencyProperty StartOpacityProperty =
DependencyProperty.Register("StartOpacity", typeof(double), typeof(LoadingIndicator),
new PropertyMetadata(1.0, new PropertyChangedCallback(StartOpacityChangedCallback)));
public static readonly DependencyProperty EndOpacityProperty =
DependencyProperty.Register("EndOpacity", typeof(double), typeof(LoadingIndicator),
new PropertyMetadata(0.1, new PropertyChangedCallback(EndOpacityChangedCallback)));
public static readonly DependencyProperty DurationProperty =
DependencyProperty.Register("Duration", typeof(TimeSpan), typeof(LoadingIndicator),
new PropertyMetadata(TimeSpan.FromSeconds(1), new PropertyChangedCallback(ValueChangedCallback)));
public static readonly DependencyProperty CountProperty =
DependencyProperty.Register("Count", typeof(int), typeof(LoadingIndicator),
new PropertyMetadata(12, new PropertyChangedCallback(CountChangedCallback)));
private static readonly DependencyProperty ControlVisibilityProperty =
DependencyProperty.Register("ControlVisibility", typeof(Visibility), typeof(LoadingIndicator),
new PropertyMetadata(Visibility.Visible, new PropertyChangedCallback(ControlVisibilityCallback)));
/// <summary>
/// Gets or sets inner Radius.
/// </summary>
public int Radius
{
get { return (int)GetValue(RadiusProperty); }
set { SetValue(RadiusProperty, value); }
}
/// <summary>
/// Gets or sets start Opacity value.
/// </summary>
public double StartOpacity
{
get { return (double)GetValue(StartOpacityProperty); }
set { SetValue(StartOpacityProperty, value); }
}
/// <summary>
/// Gets or sets end Opacity value.
/// </summary>
public double EndOpacity
{
get { return (double)GetValue(EndOpacityProperty); }
set { SetValue(EndOpacityProperty, value); }
}
/// <summary>
/// Gets or sets Duration value.
/// </summary>
public TimeSpan Duration
{
get { return (TimeSpan)GetValue(DurationProperty); }
set { SetValue(DurationProperty, value); }
}
/// <summary>
/// Gets or sets Count value.
/// </summary>
public int Count
{
get { return (int)GetValue(CountProperty); }
set { SetValue(CountProperty, value); }
}
/// <summary>
/// Gets or sets Control Visibility.
/// </summary>
private bool ControlVisibility
{
get { return (bool)GetValue(ControlVisibilityProperty); }
set { SetValue(ControlVisibilityProperty, value); }
}
private FrameworkElement AnimationElement { get; set; }
private Canvas LayoutRoot { get; set; }
/// <summary>
/// Redraw control with new parameters.
/// </summary>
/// <param name="obj"></param>
/// <param name="args"></param>
private static void ValueChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
LoadingIndicator ctl = (LoadingIndicator)obj;
ctl.CreateAnimation();
}
/// <summary>
/// Check start opacity and redraw control with new parameters.
/// </summary>
/// <param name="obj"></param>
/// <param name="args"></param>
private static void StartOpacityChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
LoadingIndicator ctl = (LoadingIndicator)obj;
ctl.StartOpacity = LoadingIndicator.CorrectOpacityValue((double)args.NewValue);
ctl.CreateAnimation();
}
/// <summary>
/// Check end opacity and redraw control with new parameters.
/// </summary>
/// <param name="obj"></param>
/// <param name="args"></param>
private static void EndOpacityChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
LoadingIndicator ctl = (LoadingIndicator)obj;
ctl.EndOpacity = LoadingIndicator.CorrectOpacityValue((double)args.NewValue);
ctl.CreateAnimation();
}
/// <summary>
/// Correct opacity value not to cross valid range borders.
/// </summary>
/// <param name="opacity">Initial opacity value.</param>
/// <returns>Corrected opacity value.</returns>
private static double CorrectOpacityValue(double opacity)
{
if (opacity < 0) return 0;
if (opacity > 1) return 1;
return opacity;
}
/// <summary>
/// Check Count property and redraw control with new parameters.
/// </summary>
/// <param name="obj"></param>
/// <param name="args"></param>
private static void CountChangedCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
LoadingIndicator ctl = (LoadingIndicator)obj;
int count = (int)args.NewValue;
if (count <= 0)
{
ctl.Count = 12;
}
ctl.CreateAnimation();
}
/// <summary>
/// Stop animation when control becomes collapsed and create it anew - when visible.
/// </summary>
/// <param name="obj"></param>
/// <param name="args"></param>
private static void ControlVisibilityCallback(DependencyObject obj, DependencyPropertyChangedEventArgs args)
{
LoadingIndicator ctl = (LoadingIndicator)obj;
Visibility visibility = (Visibility)args.NewValue;
if (ctl.LayoutRoot != null)
{
if (visibility == Visibility.Collapsed)
{
ctl.LayoutRoot.Children.Clear();
}
else
{
ctl.CreateAnimation();
}
}
}
public LoadingIndicator()
{
this.DefaultStyleKey = typeof(LoadingIndicator);
}
/// <summary>
/// Builds the visual tree when a new template is applied.
/// </summary>
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
LayoutRoot = GetTemplateChild("LayoutRoot") as Canvas;
if (LayoutRoot == null)
{
throw new NotImplementedException("Template Part LayoutRoot is required to display LoadingIndicator.");
}
AnimationElement = GetTemplateChild("PART_AnimationElement") as FrameworkElement;
if (AnimationElement == null)
{
throw new NotImplementedException("Template Part PART_AnimationElement is required to display LoadingIndicator.");
}
CreateAnimation();
}
/// <summary>
/// Copy base animation element Count times and start animation.
/// </summary>
private void CreateAnimation()
{
if (LayoutRoot != null)
{
LayoutRoot.Children.Clear();
double angle = 360.0 / this.Count;
double width = AnimationElement.Width;
double x = (Width - width) / 2;
double y = Height / 2 + Radius;
for (int i = 0; i < this.Count; i++)
{
// Copy base element
FrameworkElement element = DependencyPropertyCloner.Clone<FrameworkElement>(AnimationElement);
element.Opacity = 0;
TranslateTransform tt = new TranslateTransform() { X = x, Y = y };
RotateTransform rt = new RotateTransform() { Angle = i * angle + 180, CenterX = (width / 2), CenterY = -Radius };
TransformGroup tg = new TransformGroup();
tg.Children.Add(rt);
tg.Children.Add(tt);
element.RenderTransform = tg;
LayoutRoot.Children.Add(element);
DoubleAnimation animation = new DoubleAnimation();
animation.From = this.StartOpacity;
animation.To = this.EndOpacity;
animation.Duration = this.Duration;
animation.RepeatBehavior = RepeatBehavior.Forever;
animation.BeginTime = TimeSpan.FromMilliseconds((this.Duration.TotalMilliseconds / this.Count) * i);
Storyboard.SetTargetProperty(animation, new PropertyPath("Opacity"));
Storyboard.SetTarget(animation, element);
Storyboard sb = new Storyboard();
sb.Children.Add(animation);
sb.Begin();
}
// Bind ControlVisibilityProperty to the Visibility property
// in order to catch missing OnVisibilityChanged event
Binding binding = new Binding();
binding.Source = this;
binding.Path = new PropertyPath("Visibility");
this.SetBinding(LoadingIndicator.ControlVisibilityProperty, binding);
}
}
}
}
|
By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.
If a file you wish to view isn't highlighted, and is a text file (not binary), please
let us know and we'll add colourisation support for it.
Jevgenij lives in Riga, Latvia. He started his programmer's career in 1983 developing software for radio equipment CAD systems. Created computer graphics for TV. Developed Internet credit card processing systems for banks.
Now he is System Analyst in Accenture.