Click here to Skip to main content
15,881,600 members
Articles / Desktop Programming / WPF

C# WPF .NET 4.0 ArrowRepeatButton, NumericUpDown, and TimeCtrl Controls

Rate me:
Please Sign up or sign in to vote.
4.39/5 (11 votes)
14 Oct 2011CPOL16 min read 67.2K   3.4K   16  
User controls for entering either a time or a number within a range.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Media;
using System.Windows.Controls;
using System.Windows.Data;
using System.Globalization;
using System.Windows.Input;

namespace UpDownCtrls
{
    public enum DecimalSeparatorType : int
    {
        System_Defined,
        Point,
        Comma
    }
    public enum NegativeSignType : int
    {
        System_Defined,
        Minus
    }
    public enum NegativeSignSide : int
    {
        System_Defined,
        Prefix,
        Suffix
    }
    internal interface IFrameTxtBoxCtrl
    {
        TextBox TextBox{get;}
    }
    static class Coercer
    {
        public static void Initialize<T>() where T : UserControl
        {
            try
            {
                FrameworkPropertyMetadata BorderThicknessMetaData = new FrameworkPropertyMetadata();
                BorderThicknessMetaData.CoerceValueCallback = new CoerceValueCallback(Coercer.CoerceBorderThickness);
                UserControl.BorderThicknessProperty.OverrideMetadata(typeof(T), BorderThicknessMetaData);

                // For Background, do not do in XAML part something like:
                // Background="{Binding Background, ElementName=Root}" in TextBoxCtrl settings.
                // Reason: although this will indeed set the Background values as expected, problems arise when user
                // of control does not explicitly not set a value.
                // In this case, Background of TextBoxCtrl get defaulted to values in UserControl, which is null
                // and not what we want.
                // We want to keep the default values of a standard TextBox, which may differ according to themes.
                // Have to treat similarly as with BorderThickness...

                FrameworkPropertyMetadata BackgroundMetaData = new FrameworkPropertyMetadata();
                BackgroundMetaData.CoerceValueCallback = new CoerceValueCallback(Coercer.CoerceBackground);
                UserControl.BackgroundProperty.OverrideMetadata(typeof(T), BackgroundMetaData);

                // ... Same for BorderBrush
                FrameworkPropertyMetadata BorderBrushMetaData = new FrameworkPropertyMetadata();
                BorderBrushMetaData.CoerceValueCallback = new CoerceValueCallback(Coercer.CoerceBorderBrush);
                UserControl.BorderBrushProperty.OverrideMetadata(typeof(T), BorderBrushMetaData);
            }
            catch (Exception)
            {
            }
        }
        private delegate void FuncCoerce(IFrameTxtBoxCtrl FrameTxtBox, object value);

        private static void CommonCoerce(DependencyObject d, object value, FuncCoerce funco)
        {
            IFrameTxtBoxCtrl FrameTxtBox = d as IFrameTxtBoxCtrl;

            if (FrameTxtBox != null)
                funco(FrameTxtBox, value);
        }
        private static void FuncCoerceBorderThickness(IFrameTxtBoxCtrl FrameTxtBox, object value)
        {
            if (value is Thickness)
                FrameTxtBox.TextBox.BorderThickness = (Thickness)value;
        }
        private static void FuncCoerceBackground(IFrameTxtBoxCtrl FrameTxtBox, object value)
        {
            if (value is Brush)
                FrameTxtBox.TextBox.Background = (Brush)value;
        }
        private static void FuncCoerceBorderBrush(IFrameTxtBoxCtrl FrameTxtBox, object value)
        {
            if (value is Brush)
                FrameTxtBox.TextBox.BorderBrush = (Brush)value;
        }
        public static object CoerceBorderThickness(DependencyObject d, object value)
        {
            CommonCoerce(d, value, FuncCoerceBorderThickness);
            return new Thickness(0.0);
        }
        public static object CoerceBackground(DependencyObject d, object value)
        {
            CommonCoerce(d, value, FuncCoerceBackground);          
            return value;
        }
        public static object CoerceBorderBrush(DependencyObject d, object value)
        {
            CommonCoerce(d, value, FuncCoerceBorderBrush);  
            return value;
        }
    }
    static class SystemNumberInfo
    {
        static private NumberFormatInfo nfi;

        static SystemNumberInfo()
        {
            CultureInfo ci = CultureInfo.CurrentCulture;
            nfi = ci.NumberFormat;
        }
        public static string DecimalSeparator
        {
            get { return nfi.NumberDecimalSeparator; }
        }
        public static string NegativeSign
        {
            get { return nfi.NegativeSign; }
        }
        public static bool IsNegativePrefix
        {
            // for values, see: http://msdn.microsoft.com/en-us/library/system.globalization.numberformatinfo.numbernegativepattern.aspx
            // Assume if negative number format is (xxx), number is prefixed.
            get
            {
                return nfi.NumberNegativePattern < 3;
            }
        }
    }
    static class SystemDateInfo
    {
        static private DateTimeFormatInfo dtfi;

        static SystemDateInfo()
        {
            CultureInfo ci = CultureInfo.CurrentCulture;
            dtfi = ci.DateTimeFormat;
        }
        // Pattern tags given in http://msdn.microsoft.com/en-us/library/system.globalization.datetimeformatinfo.aspx
        public static string LongTimePattern
        {
            get { return dtfi.LongTimePattern; }
        }
        public static string AMDesignator
        {
            get { return dtfi.AMDesignator; }
        }
        public static string PMDesignator
        {
            get { return dtfi.PMDesignator; }
        }      
    }
    enum HMSType : byte
    {
        Hour,
        HHour,
        hour,
        hhour,
        minute,
        mminute,
        second,
        ssecond,
        t,
        tt,
        unknown
    }
    static class TimeCtrlExtensions
    {
        // Extension properties not allowed unfortunately, so can't write HMSType hmstype = tb.HMSType; for instance. 
        public static HMSType get_HMSType(this FrameworkElement ctrl)
        {
            HMSType hmsType;
     
            if (!Enum.TryParse(ctrl.Name, out hmsType))
                hmsType = HMSType.unknown;

            return hmsType;     
        }
        public static void set_HMSType(this FrameworkElement ctrl, HMSType hmsType)
        {
            ctrl.Name = hmsType.ToString();
        }
        public static int Get12Hour(this int Hour24)
        {
            return (Hour24 == 0)? 12 : ((Hour24 <= 12) ? Hour24 : Hour24 % 12);
        }
        public static bool IsHalfDayHour(this TextBox tb)
        {
            return tb.get_HMSType() == HMSType.hour || tb.get_HMSType() == HMSType.hhour;
        }
        public static int Get_t_Idx()
        {
            int Idx = 0;

            if (SystemDateInfo.PMDesignator[0] == SystemDateInfo.AMDesignator[0]) // case Japan.
                Idx++;

            return Idx;
        }
        public static bool IsAM_PM(this FrameworkElement ctrl)
        {
            return ctrl.get_HMSType() == HMSType.tt || ctrl.get_HMSType() == HMSType.t;
        }
        public static bool IsAlways2CharInt(this FrameworkElement ctrl)
        {
            return ((get_HMSType(ctrl) == HMSType.HHour || get_HMSType(ctrl) == HMSType.hhour ||
                get_HMSType(ctrl) == HMSType.mminute || get_HMSType(ctrl) == HMSType.ssecond));
        }
        private static string GetHMSText(FrameworkElement ctrl, DateTime dt)
        {
            string strFormat, HMSText;
            
            strFormat = ctrl.IsAlways2CharInt() ? "{0:D2}" : "{0:D}";
  
            switch (get_HMSType(ctrl))
            {
                case HMSType.Hour:
                case HMSType.HHour:
                    HMSText = string.Format(strFormat, dt.Hour);
                    break;
                case HMSType.hour:
                case HMSType.hhour:
                    HMSText = string.Format(strFormat, dt.Hour.Get12Hour());
                    break;
                case HMSType.minute:
                case HMSType.mminute:
                    HMSText = string.Format(strFormat, dt.Minute);
                    break;
                case HMSType.second:
                case HMSType.ssecond:
                    HMSText = string.Format(strFormat, dt.Second);
                    break;
                case HMSType.t:
                    HMSText = (dt.Hour / 12 == 0) ? SystemDateInfo.AMDesignator[Get_t_Idx()].ToString() : SystemDateInfo.PMDesignator[Get_t_Idx()].ToString();
                    break;
                case HMSType.tt:
                    HMSText = (dt.Hour/12 == 0)? SystemDateInfo.AMDesignator : SystemDateInfo.PMDesignator;
                    break;
                default:
                    HMSText="";
                break;
            } 
            return HMSText;
        }
        public static void set_HMSText(this TextBox tb, DateTime dt)
        {
            tb.Text = GetHMSText(tb, dt);
        }
        public static int get_Max(this TextBox tb)
        {
            switch (tb.get_HMSType())
            {
                case HMSType.Hour:
                case HMSType.HHour:
                    return 24;
                case HMSType.hour:
                case HMSType.hhour:
                    return 13;
                default:
                    return 60;
            }
        }
        public static int get_Min(this TextBox tb)
        {
            switch (tb.get_HMSType())
            {
                case HMSType.hour:
                case HMSType.hhour:
                    return 1;
                default:
                    return 0;
            }
        }
        public static DateTime ResetTime(this DateTime dt, int hms, HMSType hmsType)
        {
            return new DateTime(dt.Year, dt.Month, dt.Day,
                (hmsType == HMSType.Hour) || (hmsType == HMSType.HHour || 
                 hmsType == HMSType.hour) || (hmsType == HMSType.hhour) ? hms : dt.Hour,
                (hmsType == HMSType.minute) || (hmsType == HMSType.mminute) ? hms : dt.Minute,
                (hmsType == HMSType.second) || (hmsType == HMSType.ssecond) ? hms : dt.Second,
                dt.Millisecond, dt.Kind);
        }
        public static DateTime Reset_AM_PM_Time(this DateTime dt, bool IsAM)
        {
            int Hour = dt.Hour;

            if (IsAM && Hour >= 12)
                Hour -= 12;
            else if (!IsAM && Hour < 12)
                Hour += 12;

            return new DateTime(dt.Year, dt.Month, dt.Day, Hour, dt.Minute, dt.Second, dt.Millisecond, dt.Kind);
        }
        public static string get_TextFormat(this FrameworkElement fe)
        {
            if (fe is TextBlock)
                return ((TextBlock)fe).Text;
            else
            {
                if (get_HMSType(fe) == HMSType.tt)
                    return "{4}";
                if (get_HMSType(fe) == HMSType.t)
                    return "{5}";

                string strFormat = "{";

                switch (get_HMSType(fe))
                {
                    case HMSType.HHour: case HMSType.Hour:
                        strFormat += "0";
                        break;
                    case HMSType.hhour: case HMSType.hour:
                        strFormat += "1";
                        break;
                    case HMSType.mminute: case HMSType.minute:
                        strFormat += "2";
                        break;
                    case HMSType.ssecond: case HMSType.second:
                        strFormat += "3";
                        break;
                }
                strFormat += ":D";
                
                if ((get_HMSType(fe) == HMSType.HHour || get_HMSType(fe) == HMSType.hhour ||
                    get_HMSType(fe) == HMSType.mminute || get_HMSType(fe) == HMSType.ssecond))
                    strFormat += "2";
        
                strFormat += "}";

                return strFormat;
            }
            
        }
        public static bool IsValidTime(string strTime, string strPattern, out int Hour, out int Minute, out int Second)
        {
            // Loose validation: if for instance have an hour entry as '23' or '02', this still gets validated for an h tag.
            // Rule: if a number entry can possibly be interpreted, then it is. Allow AM/PM tag to go missing too.
            // ...but outside of this, must have a valid time and separators such as ':', '.' must be present and must match.  
            Hour = 0;
            Minute = 0;
            Second = 0;

            if (string.IsNullOrEmpty(strTime) || string.IsNullOrEmpty(strPattern))
                return false;

            bool IsValid = true;
            int Idx = 0, PatIdx = 0, Value;
            string strInt;

            while (IsValid && Idx < strTime.Length && PatIdx < strPattern.Length)
            {
                if (strPattern[PatIdx] == 'h' || strPattern[PatIdx] == 'H' || strPattern[PatIdx] == 'm' || strPattern[PatIdx] == 's')
                {
                    if (char.IsDigit(strTime, Idx))
                    {
                        strInt = strTime[Idx].ToString();

                        if (++Idx < strTime.Length && char.IsDigit(strTime, Idx))
                            strInt += strTime[Idx++].ToString();
                        
                        Value = int.Parse(strInt);

                        if (((strPattern[PatIdx] == 'h' || strPattern[PatIdx] == 'H') && Value >= 24) || Value >= 60)
                            IsValid = false;
                        else
                        {
                            if (strPattern[PatIdx] == 'h' || strPattern[PatIdx] == 'H')
                                Hour = Value;
                            else if (strPattern[PatIdx] == 'm')
                                Minute = Value;
                            else
                                Second = Value;

                            if (PatIdx + 1 < strPattern.Length && (strPattern[PatIdx] == strPattern[PatIdx + 1]))
                                PatIdx += 2;
                            else
                                PatIdx++;                    
                        }
                    }
                    else
                        IsValid = false;
                }
                else if (strPattern[PatIdx] == 't')
                {
                    bool IsPM = (strTime[Idx] == SystemDateInfo.PMDesignator[0]);

                    if (strTime[Idx] == SystemDateInfo.AMDesignator[0] || strTime[Idx] == SystemDateInfo.PMDesignator[0])
                        Idx++;

                    if (PatIdx + 1 < strPattern.Length && (strPattern[PatIdx] == strPattern[PatIdx + 1]))
                    {
                        if (Idx < strTime.Length && (strTime[Idx] == SystemDateInfo.AMDesignator[1] || strTime[Idx] == SystemDateInfo.PMDesignator[1]))
                        {
                            if (IsPM && strTime[Idx] != SystemDateInfo.PMDesignator[1])
                                IsPM = false;
                            
                            Idx++;
                        }
                        else
                            IsValid = false;
                        
                        PatIdx += 2;
                    }
                    else
                        PatIdx++;

                    if (IsPM && Hour < 12)
                        Hour += 12;
                }
                else if (strTime[Idx] == strPattern[PatIdx])
                {
                    Idx++;
                    PatIdx++;
                }
                else
                    IsValid = false;
            }
            if (Idx < strTime.Length || PatIdx < strPattern.Length)
                IsValid = false;

            return IsValid;
        }
    }
    public class ThicknessToMarginConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            if (value == null)
                throw new System.ArgumentNullException();

            if (!(value is Thickness) || !(parameter is string))
                throw new System.ArgumentException();

            bool IncrRightThickness = false;
            bool.TryParse((string)parameter, out IncrRightThickness);
            var thickness = (Thickness)value;
            return new Thickness(thickness.Left + 1.0, thickness.Top + 1.0, IncrRightThickness? thickness.Right + 18.0 : 18.0, thickness.Bottom);
        }
        public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
        {
            throw new NotSupportedException("Not Implemented.");
        }
    }
    static class LanguageStrings
    {
        static CultureInfo ci = CultureInfo.CurrentCulture;
        /*static LanguageStrings() // For testing purposes
        {
            //ci = CultureInfo.CreateSpecificCulture("de-DE");
            ci = CultureInfo.CreateSpecificCulture("fr-FR");
        }*/
        static string GetLangStr(string strTag)
        {
            return Properties.Resources.ResourceManager.GetString(strTag, ci);
        }
        public static string CopyTime { get { return GetLangStr("COPY_TIME"); }}
        public static string PasteTime { get { return GetLangStr("PASTE_TIME"); }}
        public static string ValidTimes { get { return GetLangStr("VALID_TIMES"); }}
        public static string From { get { return GetLangStr("FROM"); }}
        public static string To { get { return GetLangStr("TO"); }}
        public static string None { get { return GetLangStr("NONE"); } }
    }
    public static class TimeCtrlCustomCommands
    {
        static TimeCtrlCustomCommands()
        {
            CopyTime = new RoutedUICommand(LanguageStrings.CopyTime, "CopyTime", typeof(TimeCtrlCustomCommands));
            PasteTime = new RoutedUICommand(LanguageStrings.PasteTime, "PasteTime", typeof(TimeCtrlCustomCommands));
            ShowValidTimes = new RoutedUICommand("", "ShowValidTimes", typeof(TimeCtrlCustomCommands));
        }
        public static RoutedUICommand CopyTime { get; private set; }
        public static RoutedUICommand PasteTime { get; private set; }
        public static RoutedUICommand ShowValidTimes { get; private set; }
    }      
}

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
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions