Smallfish

Tips, Tricks, Shticks & Anything That Can Help You Be better Developer

How To Create XAML Markup Extension in WPF – Creating the Now markup extension

What?

Display a label and analog clock on screen, they should be updated “live” with the time.

How?

I use XAML Markup Extension for several reasons:

  1. It makes it easy to use it on XAML, especially to bind to it.
  2. Learn the framework extension points.
  3. Reuse – easy to use it everywhere with half line of XAML.

Show me the money!

    /// <summary>
    /// XAML Markup Extension to bind dependency property (DateTime or String)
    /// to the current date and time (updated each second)
    /// </summary>
    public class NowExtension : MarkupExtension
    {
        #region State
 
        // default, full date format (current culture)
        private readonly string m_format = 
            CultureInfo.CurrentCulture.DateTimeFormat.FullDateTimePattern;
        // for empty constructor we return the DateTime
        private readonly bool m_returnDate = false;
 
        private DependencyObject m_targetObject;
        private DependencyProperty m_targetProperty;
        private DispatcherTimer m_timer;
 
        #endregion
        #region Constructors
 
        /// <summary>
        /// Create new Now Extension that return the 
        /// current DateTime (DateTime.Now)
        /// </summary>
        public NowExtension()
        {
            m_returnDate = true;
        }
 
        /// <summary>
        /// Create new Now Extension that return the 
        /// current DateTime formatted (calling ToString 
        /// with m_format)
        /// </summary>
        public NowExtension(string format)
        {
            if (!string.IsNullOrEmpty(format))
            {
                m_format = format;
            }
        }
 
        #endregion
 
        /// <summary>
        /// Overrides MarkupExtension.ProvideValue to return 
        /// the current datetime and hook a timer to update the 
        /// target propery each second 
        /// (using DispatcherTime with Background priority)
        /// </summary>
        /// <param name="serviceProvider"></param>
        /// <returns></returns>
        public override object ProvideValue(IServiceProvider serviceProvider)
        {
            var targetHelper = 
                (IProvideValueTarget)
                serviceProvider.GetService(typeof(IProvideValueTarget));
 
            m_targetObject = 
                targetHelper.TargetObject as DependencyObject;
 
            m_targetProperty = 
                targetHelper.TargetProperty as DependencyProperty;
 
            m_timer = new DispatcherTimer(DispatcherPriority.Background);
            m_timer.Interval = TimeSpan.FromSeconds(1);
            m_timer.Tick += new EventHandler(m_timer_Tick);
            m_timer.Start();
 
            if (m_returnDate)
            {
                return DateTime.Now;
            }
 
            return GetNowValue();
        }
 
        protected virtual string GetNowValue()
        {
            return DateTime.Now.ToString(m_format);
        }
 
        void m_timer_Tick(object sender, EventArgs e)
        {
            if (m_targetObject != null && m_targetProperty != null)
            {
                object value = GetNowValue();
                if (m_returnDate)
                {
                    value = DateTime.Now;
                }
                m_targetObject.SetValue(m_targetProperty, value);
            }
        }
    }

How does it works?

The first time the ProviderValue is called, we are hooking to the target DependencyObject / DependencyProperty so we will be able to set the property on timer intervals. Then we start a timer (with interval of 1 second) and in that timer Tick event we set the new value to the hooked property, the last line just return the current value for the first time.

פורסם: Apr 19 2009, 08:46 AM by Yair Cohen | with 1 comment(s)
תגים:, , ,
שלח תגובה

(שדה חובה)  

(שדה חובה)  

(אופציונלי)

(שדה חובה) 

Please add 1 and 5 and type the answer here:


Enter the numbers above: