view MetroWpf/FxRates.UI/Controls/TimerTextBlock.cs @ 121:8f94475d3146 tip

final code
author stevenh7776
date Thu, 31 May 2012 15:35:26 +0100
parents a8b50a087544
children
line wrap: on
line source

using System;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;

namespace FxRates.UI.Controls
{
    public delegate void Invoker();

    public class TimerTextBlock : TextBlock
    {
        //private static Timer _UpdateTimer = new Timer(UpdateTimer, null, 1000, 1000);

        public static readonly DependencyProperty TimeSpanProperty =
            DependencyProperty.Register("TimeSpan", typeof (TimeSpan), typeof (TimerTextBlock),
                                        new UIPropertyMetadata(TimeSpan.Zero));

        public static readonly DependencyProperty IsStartedProperty =
            DependencyProperty.Register("IsStarted", typeof (bool), typeof (TimerTextBlock),
                                        new UIPropertyMetadata(false));

        public static readonly DependencyProperty TimeFormatProperty =
            DependencyProperty.Register("TimeFormat", typeof (string), typeof (TimerTextBlock),
                                        new UIPropertyMetadata(null));

        public static readonly DependencyProperty IsCountDownProperty =
            DependencyProperty.Register("IsCountDown", typeof (bool), typeof (TimerTextBlock),
                                        new UIPropertyMetadata(false));

        private Invoker _UpdateTimeInvoker;

        public TimerTextBlock()
        {
            Init();
        }

        public TimerTextBlock(Inline inline) : base(inline)
        {
            Init();
        }

        /// <summary>
        /// Represents the time remaining for the count down to complete if
        /// the control is initialized as a count down timer otherwise, it 
        /// represents the time elapsed since the timer has started.
        /// </summary>
        /// <exception cref="System.ArgumentException">
        /// </exception>
        public TimeSpan TimeSpan
        {
            get { return (TimeSpan) GetValue(TimeSpanProperty); }
            set
            {
                if (value < TimeSpan.Zero)
                    throw new ArgumentException();

                SetValue(TimeSpanProperty, value);
            }
        }

        // Using a DependencyProperty as the backing store for TimeSpan.  This enables animation, styling, binding, etc...

        public bool IsStarted
        {
            get { return (bool) GetValue(IsStartedProperty); }
            set { SetValue(IsStartedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsStarted. This enables animation, styling, binding, etc...

        /// <summary>
        /// Format string for displaying the time span value.
        /// </summary>
        public string TimeFormat
        {
            get { return (string) GetValue(TimeFormatProperty); }
            set { SetValue(TimeFormatProperty, value); }
        }

        // Using a DependencyProperty as the backing store for TimeFormat. This enables animation, styling, binding, etc...

        /// <summary>
        /// Represents whether the control is a CountDown or regular timer.
        /// </summary>
        public bool IsCountDown
        {
            get { return (bool) GetValue(IsCountDownProperty); }
            set { SetValue(IsCountDownProperty, value); }
        }

        public event EventHandler OnCountDownComplete;

        private static event EventHandler OnTick;

        private void Init()
        {
            Loaded += TimerTextBlock_Loaded;
            Unloaded += TimerTextBlock_Unloaded;
        }

        ~TimerTextBlock()
        {
            Dispose();
        }

        public void Dispose()
        {
            OnTick -= TimerTextBlock_OnTick;
        }

        // Using a DependencyProperty as the backing store for IsCountDown.  This enables animation, styling, binding, etc...

        /// <summary>
        /// Sets the time span to zero and stops the timer.
        /// </summary>
        public void Reset()
        {
            IsStarted = false;
            TimeSpan = TimeSpan.Zero;
        }

        private static void UpdateTimer(object state)
        {
            EventHandler onTick = OnTick;
            if (onTick != null)
                onTick(null, EventArgs.Empty);
        }

        private void TimerTextBlock_Loaded(object sender, RoutedEventArgs e)
        {
            var binding = new Binding("TimeSpan");
            binding.Source = this;
            binding.Mode = BindingMode.OneWay;
            binding.StringFormat = TimeFormat;

            SetBinding(TextProperty, binding);

            _UpdateTimeInvoker = UpdateTime;

            OnTick += TimerTextBlock_OnTick;
        }

        private void TimerTextBlock_Unloaded(object sender, RoutedEventArgs e)
        {
            OnTick -= TimerTextBlock_OnTick;
        }

        private void TimerTextBlock_OnTick(object sender, EventArgs e)
        {
            Dispatcher.Invoke(_UpdateTimeInvoker);
        }

        private void UpdateTime()
        {
            if (IsStarted)
            {
                TimeSpan step = TimeSpan.FromSeconds(1);
                if (IsCountDown)
                {
                    if (TimeSpan >= TimeSpan.FromSeconds(1))
                    {
                        TimeSpan -= step;
                        if (TimeSpan.TotalSeconds <= 0)
                        {
                            TimeSpan = TimeSpan.Zero;
                            IsStarted = false;
                            NotifyCountDownComplete();
                        }
                    }
                }
                else
                {
                    TimeSpan += step;
                }
            }
        }

        private void NotifyCountDownComplete()
        {
            EventHandler handler = OnCountDownComplete;
            if (handler != null)
                handler(this, EventArgs.Empty);
        }
    }
}