程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> .NET組件控件實例編程系列——4.多列下拉框和鼠標相關組件(一)

.NET組件控件實例編程系列——4.多列下拉框和鼠標相關組件(一)

編輯:關於.NET

網頁中浮動層的應用非常廣泛,但Windows程序中卻少有浮動層。難道Windows程序中不需要浮動層嗎 ?根據不同的需要實現相應的功能,有人會覺得直接在界面上添加控件更簡單,或者用對話窗口的方法實 現是一樣的,只要實現功能就可以了。當然,解決方法有很多種,這裡給出采用浮動層的實現方式。比如 在ComboBox控件中下拉選擇項時,只能顯示一列,而且項數很多的時候又不能查找,用一個帶查找功能的 多列下拉框會方便很多(如下圖)。

有些地方需要顯示多行信息,但空間卻比較小,像TextBox控件的Text屬性一樣,采用一個下拉文本框 來顯示和編輯,會更加靈活。

本示例包含三個組件,一個是提供下拉功能的組件DropdownComponent,一個是實現用鼠標移動控件位 置的組件MovableComponent,一個是實現用鼠標調整控件大小的組件ResizableComponent。在示例中包含 如何實現自定義可視化屬性設計器UITypeEditor,如何將一個屬性的值設置為多個枚舉以及分解成多個枚 舉,如何實現類似ToolTip給其他控件添加屬性的功能。

下面介紹各個組件的實現原理與要點:

下拉組件DropdownComponent

實現原理

1、點擊ComboBox的下拉標志時,顯示浮動控件

2、浮動控件失去焦點時,根據標志位判斷是否隱藏控件

實現要點

1、需要將ComboBox控件的DropDownHeight屬性設置為1(設置為0無效),避免出現多余的框

2、需要調整目標控件的顯示位置,不能超出窗體的邊框

3、可以根據需要不只針對ComboBox控件,只要在一個事件處理方法中顯示浮動控件即可

該組件實現起來非常簡單,主要是處理ComboBox控件的DropDown事件,以及浮動控件的Leave事件。

首先聲明內部字段和屬性

#region 字段和屬性

        private const string c_ControlCategory = "控制";

        private ComboBox m_TargetComboBox = null;
        [Category(c_ControlCategory), Description("目標下拉控件。")]
        public ComboBox TargetComboBox
        {
            get { return m_TargetComboBox; }
            set
            {
                if (this.DesignMode)
                {
                    m_TargetComboBox = value;
                }
                else
                {
                    if (m_TargetComboBox != value)
                    {
                        this.RemoveDropDownEventHandler();
                        m_TargetComboBox = value;
                        this.AddDropDownEventHandler();
                    }
                }
            }
        }

        private Control m_FloatControl = null;
        [Category(c_ControlCategory), Description("浮動控件。")]
        public Control FloatControl
        {
            get { return m_FloatControl; }
            set
            {
                if (this.DesignMode)
                {
                    m_FloatControl = value;
                }
                else
                {
                    if (m_FloatControl != value)
                    {
                        this.RemoveLeaveEventHandler();
                        m_FloatControl = value;
                        this.AddLeaveEventHanlder();
                    }
                }
            }
        }

        private bool m_AutoHide = true;
        [Category(c_ControlCategory), Description("指示在浮動控件失去焦點時自動隱藏。 "), DefaultValue(true)]
        public bool AutoHide
        {
            get { return m_AutoHide; }
            set { m_AutoHide = value; }
        }

        private DropDownControlWidthModeEnum m_FloatControlWidthMode = DropDownControlWidthModeEnum.UserDefine;
        [Category(c_ControlCategory),Description("下拉浮動控件的寬度模 式。"),DefaultValue(DropDownControlWidthModeEnum.UserDefine)]
        public DropDownControlWidthModeEnum FloatControlWidthMode
        {
            get { return m_FloatControlWidthMode; }
            set { m_FloatControlWidthMode = value; }
        }
       
        #endregion 字段和屬性

其中的FloatControlWidthMode屬性用來指示浮動控件的寬度模式,當設置為UserDefine時,按照控件 的設置尺寸顯示,當設置為AutoWidth時,調整浮動控件的寬度與下拉框的寬度相等。

下面是下拉框事件處理以及相關的方法。其中將顯示和隱藏方法重載了,一組是顯示指定的控件,一 組是用於顯示外部控件,而且都設置為public。這裡和之前用Label模擬網頁鏈接的組件一樣,可以根據 需要選擇是否公開方法,比如用其他控件控制顯示浮動控件就必須用public。還有在顯示浮動控件時,將 浮動控件添加到窗體中,這是為了避免在其他容器中,浮動控件只顯示一部分,添加到窗體後則可以完整 顯示,不會被其他容器遮擋。

#region 浮動控件操作及事件處理

        private void AddDropDownEventHandler()
        {
            if (m_TargetComboBox != null)
            {
                TargetComboBox.DropDown += new EventHandler (TargetComboBox_DropDown);
                this.m_TargetComboBox.DropDownHeight = 1;
            }
        }

        private void RemoveDropDownEventHandler()
        {
            if (m_TargetComboBox != null)
            {
                TargetComboBox.DropDown -= new EventHandler (TargetComboBox_DropDown);
                this.m_TargetComboBox.DropDownHeight = 106;
            }
        }

        private void AddLeaveEventHanlder()
        {
            if (m_FloatControl != null)
            {
                FloatControl.Leave += new EventHandler (FloatControl_Leave);
                this.m_FloatControl.Visible = false;
            }
        }

        private void RemoveLeaveEventHandler()
        {
            if (m_FloatControl != null)
            {
                FloatControl.Leave -= new EventHandler (FloatControl_Leave);
            }
        }

        void FloatControl_Leave(object sender, EventArgs e)
        {
            if (m_FloatControl != null && m_AutoHide)
                this.HideFloatControl(this.m_FloatControl);
        }

        void TargetComboBox_DropDown(object sender, EventArgs e)
        {
            if (m_FloatControl != null)
                this.ShowFloatControl(this.m_TargetComboBox, this.m_FloatControl);
        }

        /// <summary>
        /// 顯示設置的浮動控件
        /// </summary>
        public void ShowFloatControl()
        {
            this.ShowFloatControl(this.m_TargetComboBox, this.m_FloatControl);
        }

        /// <summary>
        /// 隱藏設置的浮動控件
        /// </summary>
        public void HideFloatControl()
        {
            this.HideFloatControl(this.m_FloatControl);
        }

        #endregion 浮動控件操作及事件處理


        #region 浮動控件公共操作

        /// <summary>
        /// 顯示指定的浮動控件
        /// </summary>
        /// <param name="DropdownControl">下拉控件,可以不是 ComboBox</param>
        /// <param name="FloatControl">要顯示的控件</param>
        public void ShowFloatControl(Control DropdownControl, Control FloatControl)
        {
            if (DropdownControl == null)
                throw new ArgumentNullException("DropdownControl", "指定的下 拉控件為null。");

            if (FloatControl == null)
                throw new ArgumentNullException("FloatControl", "指定要顯示的 浮動控件為null。");

            if (this.OnFloatControlDisplayChanging(FloatControl).Cancel)
                return;

            Form ParentForm = DropdownControl.FindForm();

            //將浮動控件添加到窗體上
            if (!ParentForm.Controls.Contains(FloatControl))
                ParentForm.Controls.Add(FloatControl);

            //調整浮動控件寬度
            if (this.m_FloatControlWidthMode == DropDownControlWidthModeEnum.AutoWidth)
                FloatControl.Width = DropdownControl.Width;

            //計算坐標
            Control ParentControl = DropdownControl.Parent;
            int intLeft = 0, intTop = 0;
            intLeft = DropdownControl.Left;
            intTop = DropdownControl.Top + DropdownControl.Height;

            //獲取相對窗體的位置
            while (ParentControl != ParentForm)
            {
                intLeft += ParentControl.Left;
                intTop += ParentControl.Top;
                ParentControl = ParentControl.Parent;
            }

            //判斷是否超出窗體范圍
            if (intLeft + FloatControl.Width > ParentForm.Width)
            {
                int intOffset = FloatControl.Width - DropdownControl.Width;
                if (intLeft - intOffset > 0)
                {
                    intLeft -= intOffset;
                }
                if (this.m_FloatControlWidthMode == DropDownControlWidthModeEnum.AutoWidth)
                    FloatControl.Width = FloatControl.Width - intOffset;
            }

            if (intTop + FloatControl.Height > ParentForm.Height)
            {
                int intOffset = FloatControl.Height + DropdownControl.Height;
                if (intTop - intOffset > 0)
                {
                    intTop -= intOffset;
                }
            }

            //設置浮動控件位置
            FloatControl.Left = intLeft;
            FloatControl.Top = intTop;

            //顯示浮動控件
            FloatControl.Visible = true;
            FloatControl.BringToFront();
            FloatControl.Select();

            this.OnFloatControlDisplayChanged(FloatControl);
        }

        /// <summary>
        /// 隱藏指定的浮動控件
        /// </summary>
        /// <param name="FloatControl">要隱藏的控件</param>
        public void HideFloatControl(Control FloatControl)
        {
            if (FloatControl == null)
                throw new ArgumentNullException("FloatControl", "指定要顯示的 浮動控件為null。");

            Form ParentForm = this.m_TargetComboBox.FindForm();
            if (ParentForm.Controls.Contains(FloatControl))
            {
                if (this.OnFloatControlDisplayChanging(FloatControl).Cancel)
                    return;

                ParentForm.Controls.Remove(FloatControl);
                FloatControl.SendToBack();
                FloatControl.Visible = false;

                this.OnFloatControlDisplayChanged(FloatControl);
            }
        }

        #endregion 浮動控件公共操作
        //另外組件中還添加了幾個事件,可以更靈活控制浮動控件的顯示。
        #region 內部事件及事件處理

        /// <summary>
        /// 浮動控件顯示狀態即將改變事件
        /// </summary>
        [Description("浮動控件顯示狀態即將改變事件。")]
        public event FloatControlDisplayChangingEventHandler FloatControlDisplayChanging;
        /// <summary>
        /// 浮動控件顯示狀態已改變事件
        /// </summary>
        [Description("浮動控件顯示狀態已改變事件。")]
        public event FloatControlDisplayChangdEventHandler FloatControlDisplayChanged;

        private FloatControlDisplayChangingEventArgs OnFloatControlDisplayChanging (Control FloatControl)
        {
            FloatControlDisplayChangingEventArgs myEventArgs = new FloatControlDisplayChangingEventArgs(FloatControl);
            if (this.FloatControlDisplayChanging != null)
                this.FloatControlDisplayChanging(this, myEventArgs);
            return myEventArgs;
        }

        private void OnFloatControlDisplayChanged(Control FloatControl)
        {
            if (this.FloatControlDisplayChanged != null)
                this.FloatControlDisplayChanged(this, new FloatControlDisplayChangedEventArgs(FloatControl));
        }

        #endregion 內部事件及事件處理

下面介紹鼠標相關的兩個組件,這兩個組件有一定的關聯性。

可移動組件MovableComponent

實現原理

1、鼠標移動到指定控件上,改變鼠標樣式為可移動狀態

2、按下鼠標時記錄鼠標的當前位置

3、鼠標移動時檢測是否按下左鍵,如果按下左鍵則根據當前位置和之前記錄的位置計算位移

4、根據鼠標的位移設置控件的坐標

5、鼠標離開則恢復默認鼠標樣式

實現要點

1、被移動控件和響應鼠標操作的控件不一定是同一個,比如示例中列標題響應操作,內容區域不響應 ,移動的是最外層的那個Panel。需要設置兩個屬性,一個響應操作,一個被移動,兩者可以一致。

2、響應操作的控件內部子控件也要有不同的響應,比如示例中標題欄中的圖標和標題文字響應操作, 但關閉按鈕不響應。這裡用擴展屬性實現該功能,可以給內部控件添加一個是否響應操作的屬性,讓設置 更加靈活。

本文配套源碼:http://www.bianceng.net/dotnet/201212/730.htm

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved