1. 程式人生 > >C# 自定義控制元件,日期時間選擇輸入外掛

C# 自定義控制元件,日期時間選擇輸入外掛


// 為textBox1新增一個日期時間選擇控制元件
DateTimeChoser.AddTo(textBox1);

DateTimeChoser.Designer.cs

using System;
using System.ComponentModel;
using System.Drawing;
using System.Reflection;
using System.Windows.Forms;
namespace pictureAnalyse
{
    /// <summary>  
    /// 此類用於實現一個日期時間輔助輸入外掛,呼叫邏輯:  
    /// new DateTimeChoser(textBox1);  //即可為textBox1繫結一個日期時間輸入控制元件  
    /// </summary>  
    public partial class DateTimeChoser : UserControl
    {
        public static bool showConfirmButton = true;   // 日期時間選擇時,是否顯示確定按鈕  

        /// <summary>  
        /// 為textBoox新增一個日期時間選擇控制元件,輔助日期時間的輸入  
        /// </summary>  
        public static void AddTo(TextBox textBox)
        {
            try
            {
                DateTime time = DateTime.Parse(textBox.Text);
            }
            catch (Exception ex)
            {
                textBox.Text = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss");
            }

            textBox.MouseClick += textBoox_MouseClick;
        }

        /// <summary>  
        /// 為textBoox新增一個日期時間選擇控制元件,輔助日期時間的輸入,並設定初始時顯示的時間  
        /// </summary>  
        public static void AddTo(TextBox textBoox, DateTime dateTime)
        {
            textBoox.Text = dateTime.ToString("yyyy-MM-dd HH:mm:ss");
            textBoox.MouseClick += textBoox_MouseClick;
        }

        private static void textBoox_MouseClick(object sender, MouseEventArgs e)
        {
            TextBox textBox = sender as TextBox;

            // 建立一個關聯到textBox的日期時間選擇控制元件  
            DateTimeChoser choser = new DateTimeChoser();
            choser.showOn(textBox);

            // 設定顯示的時間為文字框中的日期時間  
            try
            {
                DateTime time = DateTime.Parse(textBox.Text);
                choser.setDateTime(time);
            }
            catch (Exception ex) { }
        }

        public DateTimeChoser()
        {
            InitializeComponent();
            init();
        }

        private void init()
        {
            // 時分秒設定  
            for (int i = 0; i < 24; i++) comboBox_hour.Items.Add((i < 10 ? "0" : "") + i);
            for (int i = 0; i < 60; i = i + 1) comboBox_minite.Items.Add((i < 10 ? "0" : "") + i);
            for (int i = 0; i < 60; i++) comboBox_second.Items.Add((i < 10 ? "0" : "") + i);

            comboBox_hour.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBox_minite.DropDownStyle = ComboBoxStyle.DropDownList;
            comboBox_second.DropDownStyle = ComboBoxStyle.DropDownList;

            //設定顯示的日期時間  
            setDateTime(DateTime.Now);
        }

        public delegate void DateTimeChanged_Handle(object sender, EventArgs e);
        [Description("當選擇日期或時間變動時,呼叫此事件"), Category("自定義事件")]
        public event DateTimeChanged_Handle DateTimeChanged;

        // 選擇日期變動  
        private void monthCalendar1_DateSelected(object sender, DateRangeEventArgs e)
        {
            DateTime S = monthCalendar1.SelectionStart;
            string date = S.ToString("yyyy-MM-dd");
            if (!date.Equals(label_date.Text))
            {
                label_date.Text = date;
                if (DateTimeChanged != null) DateTimeChanged(this, new EventArgs());
            }
        }

        //選擇的時間變動  
        private void TimeChanged(object sender, EventArgs e)
        {
            string time = comboBox_hour.Text + ":" + comboBox_minite.Text + ":" + comboBox_second.Text;
            if (!time.Equals(label_time.Text))
            {
                label_time.Text = time;
                if (DateTimeChanged != null) DateTimeChanged(this, new EventArgs());
            }
        }

        // 設定顯示到指定的日期時間  
        public void setDateTime(DateTime now)
        {
            // 初始時介面顯示當前的日期時間  
            label_date.Text = now.ToString("yyyy-MM-dd");
            monthCalendar1.SetDate(now);

            // 設定時間  
            label_time.Text = now.ToString("HH:mm:ss");
            comboBox_hour.SelectedIndex = now.Hour;
            comboBox_minite.SelectedIndex = now.Minute;
            comboBox_second.SelectedIndex = now.Second;
        }

        // 獲取當前選擇的日期時間  
        public string getDateTime()
        {
            return label_date.Text + " " + label_time.Text;
        }


        # region 自定義控制元件輸入繫結邏輯,將當前日期時間控制元件繫結到指定的TextBox

        private Form form;
        TextBox textbox;
        private Delegate[] textboxEvents;

        // 在指定的TextBox中,顯示當前日期時間選擇控制元件,進行日期時間的輸入  
        public void showOn(TextBox textBox, int offX = 0, int offY = 0)
        {
            Point P = getLocation(textBox);
            P = new Point(P.X, P.Y + textBox.Height);

            show(textBox, P.X + offX, P.Y + offY, showConfirmButton);
        }

        // 在TextBox點選時,呼叫DateTimeChoser進行日期時間的選擇,當再次點選時,關閉之前的日期選擇狀態  
        private void show(TextBox textbox, int L, int T, bool showButton)
        {
            this.textbox = textbox;
            textboxEvents = getEvents(textbox, "MouseClick");  // 獲取TextBox原有事件處理邏輯  
            ClearEvent(textbox, "MouseClick");          // 移除TextBox原有MouseClick事件處理邏輯  

            // 新建一個窗體  
            form = new Form();
            form.Width = this.Width;
            form.Height = this.Height;
            if (showButton) form.Height = this.Height + 40;
            form.FormBorderStyle = FormBorderStyle.None;    // 無邊框  
            form.ShowInTaskbar = false;                     // 不在工作列中顯示  
            form.BackColor = Color.White;                   //   

            form.Location = new Point(L, T);

            // 將當前日期時間選擇控制元件新增到form中  
            this.Left = 0; this.Top = 0;
            form.Controls.Add(this);

            if (showButton)
            {
                Button button = new Button();
                button.Text = "確定";
                button.ForeColor = Color.Blue;
                button.Left = (this.Width - button.Width) / 2;
                button.Top = this.Height + (40 - button.Height) / 2;
                form.Controls.Add(button);

                button.Click += button_Click;
            }

            form.Show();             // 顯示日期時間選擇  
            form.Location = new Point(L, T);
            form.TopMost = true;
            form.Activate();         // 當前介面獲取到焦點  

            Form Parent = getParentForm(textbox);       // 獲取TextBox的父窗體  
            if (Parent != null) Parent.FormClosed += Parent_FormClosed;

            textbox.MouseClick += textbox_MouseClick;
        }

        // 新增  
        private void button_Click(object sender, EventArgs e)
        {
            textbox_MouseClick(textbox, null);
        }

        // 關閉當前form  
        private void Parent_FormClosed(object sender, FormClosedEventArgs e)
        {
            if (form != null)
            {
                form.Close();
                form = null;
            }
        }

        private void textbox_MouseClick(object sender, MouseEventArgs e)
        {
            TextBox textBox = sender as TextBox;
            textBox.Text = getDateTime();

            if (form != null)
            {
                form.Close();
                form = null;
            }

            textBox.MouseClick -= textbox_MouseClick;           // 移除當前事件處理邏輯  
            addEvents(textBox, "MouseClick", textboxEvents);    // 還原TextBox原有事件處理邏輯  
        }

        # endregion


        // 獲取給定控制元件的父窗體  
        public static Form getParentForm(Control control)
        {
            if (control is Form) return control as Form;

            Control C = control;
            while (C.Parent != null)
            {
                if (C.Parent is Form) return C.Parent as Form;
                else C = C.Parent;
            }

            return null;
        }

        #region 獲取控制元件的座標資訊

        /// <summary>  
        /// 獲取任意控制元件相對於螢幕的座標  
        /// </summary>  
        public static Point getLocation(Control control)
        {
            Point P;
            if (control is Form) P = getFormClientLocation(control as Form);
            else P = control.Location;
            if (control.Parent != null)
            {
                Control parent = control.Parent;
                Point P2 = getLocation(parent);

                P = new Point(P.X + P2.X, P.Y + P2.Y);
            }

            return P;
        }

        /// <summary>  
        /// 獲取Form窗體有效顯示區域的起點,相對於螢幕的座標  
        /// </summary>  
        public static Point getFormClientLocation(Form form)
        {
            Rectangle rect = form.ClientRectangle;

            int offx = 0, offy = 0;
            if (form.FormBorderStyle != FormBorderStyle.None)
            {
                offx = (form.Width - rect.Width) / 2;
                offy = (form.Height - rect.Height) - 8;
            }

            Point P = new Point(form.Location.X + offx, form.Location.Y + offy);

            return P;
        }

        # endregion


        # region 動態修改控制元件對應的事件處理邏輯

        // ClearEvent(button1,"Click");//就會清除button1物件的Click事件的所有掛接事件。  
        private void ClearEvent(Control control, string eventname)
        {
            if (control == null) return;
            if (string.IsNullOrEmpty(eventname)) return;
            BindingFlags mPropertyFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic;
            BindingFlags mFieldFlags = BindingFlags.Static | BindingFlags.NonPublic;
            Type controlType = typeof(System.Windows.Forms.Control);
            PropertyInfo propertyInfo = controlType.GetProperty("Events", mPropertyFlags);
            EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(control, null);
            FieldInfo fieldInfo = (typeof(Control)).GetField("Event" + eventname, mFieldFlags);
            Delegate d = eventHandlerList[fieldInfo.GetValue(control)];
            if (d == null) return;
            EventInfo eventInfo = controlType.GetEvent(eventname);
            foreach (Delegate dx in d.GetInvocationList())
                eventInfo.RemoveEventHandler(control, dx);
        }

        // getEvent(button1,"Click"); //就會獲取到button1物件的Click事件的所有掛接事件。  
        private Delegate[] getEvents(Control control, string eventname)
        {
            if (control == null) return null;
            if (string.IsNullOrEmpty(eventname)) return null;
            BindingFlags mPropertyFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.Static | BindingFlags.NonPublic;
            BindingFlags mFieldFlags = BindingFlags.Static | BindingFlags.NonPublic;
            Type controlType = typeof(System.Windows.Forms.Control);
            PropertyInfo propertyInfo = controlType.GetProperty("Events", mPropertyFlags);
            EventHandlerList eventHandlerList = (EventHandlerList)propertyInfo.GetValue(control, null);
            FieldInfo fieldInfo = (typeof(Control)).GetField("Event" + eventname, mFieldFlags);
            Delegate d = eventHandlerList[fieldInfo.GetValue(control)];
            if (d == null) return null;

            Delegate[] events = new Delegate[d.GetInvocationList().Length];
            int i = 0;
            foreach (Delegate dx in d.GetInvocationList()) events[i++] = dx;

            return events;
        }

        // addEvents(button1,"Click"); // 為button1物件的Click事件掛接事件  
        private void addEvents(Control control, string eventname, Delegate[] evenets)
        {
            if (control == null) return;
            if (string.IsNullOrEmpty(eventname)) return;

            Type controlType = typeof(System.Windows.Forms.Control);
            EventInfo eventInfo = controlType.GetEvent(eventname);

            foreach (Delegate e in evenets)
                eventInfo.AddEventHandler(control, e);
        }

        # endregion

    }

}
DateTimeChoser.cs
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace pictureAnalyse
{
    partial class DateTimeChoser
    {
        /// <summary> 
        /// 必需的設計器變數。
        /// </summary>
        private System.ComponentModel.IContainer components = null;

        /// <summary> 
        /// 清理所有正在使用的資源。
        /// </summary>
        /// <param name="disposing">如果應釋放託管資源,為 true;否則為 false。</param>
        protected override void Dispose(bool disposing)
        {
            if (disposing && (components != null))
            {
                components.Dispose();
            }
            base.Dispose(disposing);
        }

        #region 元件設計器生成的程式碼

        /// <summary> 
        /// 設計器支援所需的方法 - 不要
        /// 使用程式碼編輯器修改此方法的內容。
        /// </summary>
        private void InitializeComponent()
        {
            this.monthCalendar1 = new System.Windows.Forms.MonthCalendar();
            this.panel_consume = new System.Windows.Forms.Panel();
            this.label6 = new System.Windows.Forms.Label();
            this.comboBox_second = new System.Windows.Forms.ComboBox();
            this.label5 = new System.Windows.Forms.Label();
            this.comboBox_minite = new System.Windows.Forms.ComboBox();
            this.label4 = new System.Windows.Forms.Label();
            this.comboBox_hour = new System.Windows.Forms.ComboBox();
            this.panel1 = new System.Windows.Forms.Panel();
            this.label_date = new System.Windows.Forms.Label();
            this.label_time = new System.Windows.Forms.Label();
            this.panel2 = new System.Windows.Forms.Panel();
            this.panel_consume.SuspendLayout();
            this.panel1.SuspendLayout();
            this.panel2.SuspendLayout();
            this.SuspendLayout();
            // 
            // monthCalendar1
            // 
            this.monthCalendar1.AllowDrop = true;
            this.monthCalendar1.Location = new System.Drawing.Point(-3, 15);
            this.monthCalendar1.Name = "monthCalendar1";
            this.monthCalendar1.TabIndex = 0;
            this.monthCalendar1.DateSelected += new System.Windows.Forms.DateRangeEventHandler(this.monthCalendar1_DateSelected);
            // 
            // panel_consume
            // 
            this.panel_consume.BackColor = System.Drawing.Color.White;
            this.panel_consume.Controls.Add(this.label6);
            this.panel_consume.Controls.Add(this.comboBox_second);
            this.panel_consume.Controls.Add(this.label5);
            this.panel_consume.Controls.Add(this.comboBox_minite);
            this.panel_consume.Controls.Add(this.label4);
            this.panel_consume.Controls.Add(this.comboBox_hour);
            this.panel_consume.Location = new System.Drawing.Point(-2, 173);
            this.panel_consume.Name = "panel_consume";
            this.panel_consume.Size = new System.Drawing.Size(222, 30);
            this.panel_consume.TabIndex = 23;
            // 
            // label6
            // 
            this.label6.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.label6.AutoSize = true;
            this.label6.Location = new System.Drawing.Point(195, 10);
            this.label6.Name = "label6";
            this.label6.Size = new System.Drawing.Size(17, 12);
            this.label6.TabIndex = 15;
            this.label6.Text = "秒";
            // 
            // comboBox_second
            // 
            this.comboBox_second.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.comboBox_second.FormattingEnabled = true;
            this.comboBox_second.Location = new System.Drawing.Point(149, 6);
            this.comboBox_second.Name = "comboBox_second";
            this.comboBox_second.Size = new System.Drawing.Size(40, 20);
            this.comboBox_second.TabIndex = 14;
            this.comboBox_second.Text = "0";
            this.comboBox_second.SelectedIndexChanged += new System.EventHandler(this.TimeChanged);
            // 
            // label5
            // 
            this.label5.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.label5.AutoSize = true;
            this.label5.Location = new System.Drawing.Point(126, 10);
            this.label5.Name = "label5";
            this.label5.Size = new System.Drawing.Size(17, 12);
            this.label5.TabIndex = 13;
            this.label5.Text = "分";
            // 
            // comboBox_minite
            // 
            this.comboBox_minite.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.comboBox_minite.FormattingEnabled = true;
            this.comboBox_minite.Location = new System.Drawing.Point(80, 6);
            this.comboBox_minite.Name = "comboBox_minite";
            this.comboBox_minite.Size = new System.Drawing.Size(40, 20);
            this.comboBox_minite.TabIndex = 12;
            this.comboBox_minite.Text = "0";
            this.comboBox_minite.SelectedIndexChanged += new System.EventHandler(this.TimeChanged);
            // 
            // label4
            // 
            this.label4.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.label4.AutoSize = true;
            this.label4.Location = new System.Drawing.Point(57, 10);
            this.label4.Name = "label4";
            this.label4.Size = new System.Drawing.Size(17, 12);
            this.label4.TabIndex = 11;
            this.label4.Text = "時";
            // 
            // comboBox_hour
            // 
            this.comboBox_hour.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
            this.comboBox_hour.FormattingEnabled = true;
            this.comboBox_hour.Location = new System.Drawing.Point(9, 6);
            this.comboBox_hour.Name = "comboBox_hour";
            this.comboBox_hour.Size = new System.Drawing.Size(42, 20);
            this.comboBox_hour.TabIndex = 10;
            this.comboBox_hour.Text = "0";
            this.comboBox_hour.SelectedIndexChanged += new System.EventHandler(this.TimeChanged);
            // 
            // panel1
            // 
            this.panel1.BackColor = System.Drawing.Color.White;
            this.panel1.Controls.Add(this.label_date);
            this.panel1.Controls.Add(this.label_time);
            this.panel1.Location = new System.Drawing.Point(-3, -1);
            this.panel1.Name = "panel1";
            this.panel1.Size = new System.Drawing.Size(223, 23);
            this.panel1.TabIndex = 25;
            // 
            // label_date
            // 
            this.label_date.AutoSize = true;
            this.label_date.BackColor = System.Drawing.Color.White;
            this.label_date.Font = new System.Drawing.Font("宋體", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.label_date.Location = new System.Drawing.Point(18, 3);
            this.label_date.Name = "label_date";
            this.label_date.Size = new System.Drawing.Size(98, 16);
            this.label_date.TabIndex = 26;
            this.label_date.Text = "2016-06-12";
            // 
            // label_time
            // 
            this.label_time.AutoSize = true;
            this.label_time.BackColor = System.Drawing.Color.White;
            this.label_time.Font = new System.Drawing.Font("宋體", 12F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.label_time.Location = new System.Drawing.Point(118, 3);
            this.label_time.Name = "label_time";
            this.label_time.Size = new System.Drawing.Size(80, 16);
            this.label_time.TabIndex = 25;
            this.label_time.Text = "12:23:35";
            // 
            // panel2
            // 
            this.panel2.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
            this.panel2.Controls.Add(this.panel1);
            this.panel2.Controls.Add(this.panel_consume);
            this.panel2.Controls.Add(this.monthCalendar1);
            this.panel2.Location = new System.Drawing.Point(0, 0);
            this.panel2.Name = "panel2";
            this.panel2.Size = new System.Drawing.Size(215, 202);
            this.panel2.TabIndex = 26;
            // 
            // DateTimeChoser
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.panel2);
            this.Name = "DateTimeChoser";
            this.Size = new System.Drawing.Size(215, 202);
            this.panel_consume.ResumeLayout(false);
            this.panel_consume.PerformLayout();
            this.panel1.ResumeLayout(false);
            this.panel1.PerformLayout();
            this.panel2.ResumeLayout(false);
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.MonthCalendar monthCalendar1;
        private System.Windows.Forms.Panel panel_consume;
        private System.Windows.Forms.Label label6;
        private System.Windows.Forms.ComboBox comboBox_second;
        private System.Windows.Forms.Label label5;
        private System.Windows.Forms.ComboBox comboBox_minite;
        private System.Windows.Forms.Label label4;
        private System.Windows.Forms.ComboBox comboBox_hour;
        private System.Windows.Forms.Panel panel1;
        private System.Windows.Forms.Label label_date;
        private System.Windows.Forms.Label label_time;
        private System.Windows.Forms.Panel panel2;
    }
}

新增以上兩個類到專案,編譯執行一次。自定義的DateTimeChoser控制元件會出現在工具箱中。

可直接拖拽至Form窗體中使用,也可通過程式碼進行呼叫。