WinForm公司專屬應用程式架構設計【四】動態建立業務表單

來源:互聯網
上載者:User

閑話休提~

一:自訂Tab按鈕

我們的tab按鈕左部是文字;右部是關閉按鈕;

此按鈕有兩種狀態:選中和未選中

未選中的按鈕滑鼠滑上背景色會變為淡藍色;

選中的按鈕背景色是黃色

關閉按鈕滑鼠滑上去是深黃色

 

控制項中涉及的屬性和公開的事件屬性

     /// <summary>        /// Tab標題        /// </summary>        public string Caption;        /// <summary>        /// 是否選中        /// </summary>        bool IsSelected = true;        /// <summary>        /// 文字的顏色        /// </summary>        Color StrColor = Color.Black;        /// <summary>        /// 寬度        /// </summary>        int StrWidth;        /// <summary>        /// 選中事件        /// </summary>        [Browsable(true)]        [EditorBrowsable(EditorBrowsableState.Always)]        public event EventHandler OnSelect;        /// <summary>        /// 單擊關閉按鈕事件        /// </summary>        [Browsable(true)]        [EditorBrowsable(EditorBrowsableState.Always)]        public event EventHandler OnClose;
 

注釋還是比較清楚的,就不多說了

接著看這個控制項自己的事件

        /// <summary>        /// 滑鼠移入事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void TabBTN_MouseEnter(object sender, EventArgs e)        {            if (!IsSelected)            {                this.BackColor = ColorTranslator.FromHtml("#4D6082");            }        }        /// <summary>        /// 滑鼠移出事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void TabBTN_MouseLeave(object sender, EventArgs e)        {            if (!IsSelected)            {                this.BackColor = ColorTranslator.FromHtml("#293955");            }        }        /// <summary>        /// 滑鼠移動事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void TabBTN_MouseMove(object sender, MouseEventArgs e)        {            var flag = IsMouseOnClosePoint();            if (flag)            {                DrawControl(Color.Black, Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(232)))), ((int)(((byte)(166))))));            }            else            {                DrawControl(StrColor, this.BackColor);            }        }        /// <summary>        /// 重繪事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void TabBTN_Paint(object sender, PaintEventArgs e)        {            DrawControl(StrColor, this.BackColor);        }
 

移入和移出事件都是要觸發移動事件的

移動事件要先判斷滑鼠所在的位置,是不是出於關閉按鈕位置;

然後再根據滑鼠的位置以不同的顏色繪製控制項

下面看繪製控制項和判斷滑鼠位置的相關方法

        /// <summary>        /// 重寫建立事件        /// </summary>        protected override void OnCreateControl()        {            base.OnCreateControl();            var g = this.CreateGraphics();            StrWidth = (int)g.MeasureString(Caption, SystemFonts.DefaultFont).Width;            g.Dispose();            this.Width = StrWidth + 24;        }        /// <summary>        /// 繪製控制項        /// </summary>        /// <param name="fore"></param>        /// <param name="bg"></param>        void DrawControl(Color fore, Color bg)        {            var g = this.CreateGraphics();            g.DrawString(Caption, SystemFonts.DefaultFont, new SolidBrush(StrColor), new PointF(3, 8));            var p = new Pen(fore, (float)1);            g.FillRectangle(new SolidBrush(bg), new Rectangle(StrWidth + 6, 7, 13, 13));            g.TranslateTransform(StrWidth + 12, 13);            g.RotateTransform(45);            for (var i = 0; i < 4; i++)            {                g.RotateTransform(90);                g.DrawLine(p, 0, 0, 6, 0);            }            g.ResetTransform();            p.Dispose();            g.Dispose();        }        /// <summary>        /// 滑鼠位置        /// </summary>        /// <returns></returns>        public bool IsMouseOnClosePoint()        {            var p = this.PointToClient(MousePosition);            var crx = new Rectangle(StrWidth + 3, 3, 16, 16);            return crx.Contains(p);        }
 

我們在建立控制項的時候得到了文本的寬度

根據這個寬度來繪製控制項文本和關閉按鈕的位置

 

我們在屬性裡為這個控制項定義了事件的handler

下面看看這些handler是怎麼觸發的

/// <summary>        /// 取消選中        /// </summary>        public void DisSelectMe()        {            IsSelected = false;            this.BackColor = ColorTranslator.FromHtml("#293955");            StrColor = Color.White;            DrawControl(StrColor, this.BackColor);        }        /// <summary>        /// 選擇中        /// </summary>        public void SelectMe()        {            IsSelected = true;            this.BackColor = SystemColors.Info;            StrColor = Color.Black;            DrawControl(StrColor, this.BackColor);        }        /// <summary>        /// 觸發自訂事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        private void TabBTN_Click(object sender, EventArgs e)        {            var flag = IsMouseOnClosePoint();            if (flag)            {                OnClose(this, EventArgs.Empty);            }            else            {                if (IsSelected)                {                    return;                }                OnSelect(this, EventArgs.Empty);                SelectMe();            }        }
 

到此為止完成了tab按鈕的製作

可能有些地方還做的不是很完美~歡迎批評指正

二:業務表單的基類

所有的業務表單都繼承自這個基類BaseForm

這個表單基類有三個公開的屬性

        /// <summary>        /// 菜單資料        /// </summary>        public MenuModel FormMenu { get; set; }        /// <summary>        /// tab按鈕        /// </summary>        public TabBTN FormTabBTN { get; set; }        /// <summary>        /// 子功能表        /// </summary>        public Label SubMenu { get; set; }
 

這三個屬性在後面會用到

這裡先不說了

        /// <summary>        /// 建構函式        /// </summary>        public BaseForm()        {            InitializeComponent();            this.TopLevel = false;        }
 

一般頂層表單是不允許被當作子控制項放在容器控制項中的

所以我們要設定表單的TopLevel屬性

        /// <summary>        /// tab按鈕選中事件;        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        public virtual void tbn_OnSelect(object sender, EventArgs e)        {            this.Show();        }        /// <summary>        /// tab按鈕關閉事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        public virtual void tbn_OnClose(object sender, EventArgs e)        {            this.Close();        }
 

這是tab按鈕的兩個事件~

在建立tab按鈕的時候註冊的~

待會我們再說怎麼建立的tab按鈕和註冊這兩個事件~

因為並不是在baseForm裡建立的tab按鈕

        private void BaseForm_VisibleChanged(object sender, EventArgs e)        {            if (Utils.IsInDesignMode())            {                return;            }            this.VisibleChanged -= new EventHandler(BaseForm_VisibleChanged);            var mf = Utils.GetMainForm();            if (this.Visible)            {                foreach (var hf in mf.FormHistory)                {                    if (hf.FormMenu.Url.Equals(this.FormMenu.Url))                    {                        continue;                    }                    if (hf.Visible)                    {                        hf.Hide();                    }                }                FormTabBTN.SelectMe();                mf.FormHistory.Remove(this);                mf.FormHistory.Insert(0, this);                mf.MainContainerP.Controls.Clear();                mf.MainContainerP.Controls.Add(this);                SubMenu.BackColor = SystemColors.Info;                //TODO:系統名稱可以做到資料庫裡去                mf.Text = string.Format("XXX管理系統-{0}", FormMenu.MenuName);            }            else            {                                FormTabBTN.DisSelectMe();                SubMenu.BackColor = Color.Transparent;            }            this.VisibleChanged += new EventHandler(BaseForm_VisibleChanged);        }
 

這是BaseForm的一個重要事件

隱藏和顯示切換的時候被觸發

如果從隱藏變為顯示

先遍曆所有開啟過的業務表單,如果有是顯示狀態的,那麼就把他隱藏掉,因為當前系統只能有一個業務表單是出於顯示狀態的

接著選中TAB按鈕,

FormHistory的Remove和Insert主要是為了讓系統記住哪些表單是最近顯示過的;

MainContainerP的Clear和Add是為了讓表單顯示在容器控制項內

如果從顯示變為隱藏

TAB按鈕取消選中,

子功能表的背景顏色變成透明的,(其實就是子功能表取消選中)

事件處理的開始取消了事件註冊

事件處理的結束有把事件註冊進去了

這樣做主要是為了避免多次觸發事件

Utils.GetMainForm();擷取主視窗的代碼如下:

        /// <summary>        /// 主視窗        /// </summary>        private static MainForm mf;        /// <summary>        /// 擷取主視窗        /// </summary>        /// <returns></returns>        public static MainForm GetMainForm()        {            if (mf == null)            {                mf = Application.OpenForms["MainForm"] as MainForm;            }            return mf;        }
 

當業務表單關閉時要處理一些邏輯

代碼如下

        private void BaseForm_FormClosing(object sender, FormClosingEventArgs e)        {            this.VisibleChanged -= new EventHandler(BaseForm_VisibleChanged);            var mf = Utils.GetMainForm();            mf.FormHistory.Remove(this);            this.SubMenu.BackColor = Color.Transparent;            if (mf.FormHistory.Count > 0)            {                mf.FormHistory[0].Show();            }            foreach (var f in mf.FormHistory)            {                if (f.FormTabBTN.Left > FormTabBTN.Left)                {                    f.FormTabBTN.Left -= (FormTabBTN.Width + 6);                }            }            mf.TabContainerP.Controls.Remove(FormTabBTN);        }
 

取消事件註冊

移除記錄

取消子功能表選中

開啟最近一次開啟的業務表單(如果有的話)

重寫設定tab按鈕的位置(主要是被關閉的tab按鈕的右邊的tab按鈕)

刪除tab按鈕

三:動態建立業務表單

我們在上一節中只講了子功能表的滑入和滑出事件,而沒有講單擊事件

單擊事件就是建立業務表單的事件了

來看一下代碼

        /// <summary>        /// 子功能表彈起事件        /// </summary>        /// <param name="sender"></param>        /// <param name="e"></param>        void sm_MouseUp(object sender, MouseEventArgs e)        {            var lb = sender as Label;            var m = lb.Tag as MenuModel;            if (string.IsNullOrEmpty(m.Url))            {                Utils.Alert("沒有與此菜單相關的業務表單");                return;            }            BaseForm f = null;            foreach(var hf in FormHistory)            {                if (hf.FormMenu.Url.Equals(m.Url))                {                    f = hf;                    break;                }            }            if (f == null)            {                f = CreateOneForm(m);                f.SubMenu = lb;            }            if (f != null&&!f.Visible)            {                f.Show();            }        }
 

其實這個方法裡的商務邏輯不多

主要的還是f = CreateOneForm(m);這一句

        /// <summary>        /// 建立一個業務表單;包括tab按鈕        /// </summary>        /// <param name="m"></param>        private BaseForm CreateOneForm(MenuModel m)        {            var ass = this.GetType().Assembly;            var url = string.Format("XL.Client.Forms.{0}", m.Url);            BaseForm f = null;            try            {                f = ass.CreateInstance(url) as BaseForm;            }            catch            {                Utils.Alert("沒有與此菜單相關的業務表單");                return null;            }            f.Dock = DockStyle.Fill;            f.FormMenu = m;            var tabBtn = new TabBTN();            tabBtn.OnClose += new EventHandler(f.tbn_OnClose);            tabBtn.OnSelect += new EventHandler(f.tbn_OnSelect);            tabBtn.Caption = m.MenuName;            int left = 6;            var tabCount = TabContainerP.Controls.Count;            if (tabCount > 0)            {                var lastTab = TabContainerP.Controls[tabCount - 1];                left += (lastTab.Left + lastTab.Width);            }            tabBtn.Left = left;            TabContainerP.Controls.Add(tabBtn);            f.FormTabBTN = tabBtn;            return f;        }
 

我們把菜單的URL欄位拿出來,反射了一個業務表單的執行個體

然後建立了tab按鈕的執行個體,並讓這個業務表單持有這個執行個體

注意tab按鈕的close和select事件是怎麼註冊的哦~ 親~

 

好吧~就這些~

今天的內容比較多~

寫的匆忙~有問題大家盡情的提吧~

接下來的內容是:登入、閃屏、用戶端快取資料、WCF安全驗證

 

大叔~大嬸~大哥~大嫂~大妹子~點個推薦吧~點個推薦吧~
相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.