Click here to Skip to main content
15,886,362 members
Articles / Desktop Programming / XAML

A Silverlight application with the WCF RIA Services Class Library

Rate me:
Please Sign up or sign in to vote.
4.72/5 (11 votes)
3 Mar 2010CPOL8 min read 62.7K   1.8K   39  
A Silverlight application using the WCF RIA Services Class Library. Demonstrates how to implement a custom Authorization Service, utilize localized resources, and add unit tests for DAL.

// 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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Latvia Latvia
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.

Comments and Discussions