文章出處

個人理解,開發應用程序的目的,不論是B/S或是C/S結構類型,無非就是實現可供用戶進行查、增、改、刪,其中查詢用到最多,開發設計的場景也最為復雜,包括但不限于:表格記錄查詢、報表查詢、導出文件查詢等等,其次就是增加、更改、刪除,我這里統稱為編輯,而編輯在開發設計中的場景就顯得較為通用,大多都采用編輯組件(文本框、下拉框、選擇框、數字框等)來供用戶進行編輯操作,由于查詢的開發設計場景需與實際的數據及客戶要求來進行的,所以在此不作討論,本文主要講述的是如何利用FlowLayoutPanel及我(夢在旅途)自定義的編輯控件來實現快速構建C/S版的編輯表單頁面。

有經歷過開發ASP.NET MVC網站的人都知道,在構建編輯頁面時,我們可以通過HtmlHelper擴展類相關方法來快速生成相應的編輯控件,如:Html.LabelFor,Html.TextBoxFor等等,而在Winform 項目中卻并沒有類似的方法可以讓我們快速構建編輯表單頁面,所以為了減輕我們經常遇到,又比較耗時,且沒有任何技術含量的開發工作量,我開發了類似的編輯控件系列,包括:CTextBox【文本框】、CPictureBox【圖片框】、CNumberBox【數字框】、CDropDownBox【下拉框】、CDisplayBox【顯示框】、CCheckBox【勾選框】,這些控件都一些共有特性,如:Label:顯示編輯項目名稱,Value:控件的值,ValueFor<TEntity>:快速設置控件相關屬性的方法,這些共有特性是實現快速構造編輯控件的關鍵,當然每種編輯控件還有自己獨特的屬性,如:CTextBox可以設置是否顯示按鈕,是否只讀,是否多行等,CNumberBox可以設置小數位、最大值與最小值等,由于這些控件的代碼加起來可能比較多,我這里僅以CTextBox為例來進行分析與說明,CTextBox是屬性最多的控件。

首先還是看一下CTextBox控件的界面設計,如下圖:

從圖中可以看出,CTextBox控件由一個TableLayouPanel、一個Label、一個TextBox、一個Button共同組成:

TableLayouPanel作為控件的頂層容器,其DOCK屬性設置為Fill,實現占據整個控件,另外分別設有一行三列,第一列寬度設為自動調整,第二列寬度設為100%,第三列寬度設為自動調整,如下圖:

 TableLayouPanel這樣設計的目的是:實現第一列的寬度依據LABEL的內容自動調整,第二列的寬度為TextBox的寬度,第三列的寬度為Button的寬度,這樣一來,我們在改變CTextBox的整個大小時,確保布局一致性(即:在CTextBox總寬度內,TextBox的寬度是CTextBox總寬度-LABEL與Button的實際寬度)

Label控件作為顯示編輯項目名稱部份,它的屬性AutoSize設為True,Anchor設為Left,設計目的:實現在第一列中向左居中,且寬度依據實際內容而改變

 TextBox控件作為可供編輯內容部份,它的屬性設Anchor設為Top, Bottom, Left, Right,設計目的:實現 TextBox控件占據整個第二列,即若控件的寬度與高度改變,TextBox控件也會跟著改變,這個很重要哦!

Button控件為可選部份,若需要用到控件的值來源于其它選項(如:瀏覽文件、保存文件等),則可將其CTextBox.DispalyOpenButton設為True即可,同樣,它的屬性Anchor設為Left,并調整好固定的寬度與高度,設計目的:實現在第三列中向左居中,且寬度不變

實現的整體效果如下圖示:

 

我這里用紅線框出來了,大家看出效果來了嗎?也就是我直接拖放了三個CTextBox控件,然后分別將LABEL的內容設置為不相同,除非手動改變控件寬度,否則每個控件寬度均相同,這樣再結合FlowLayoutPanel控件的流式布局(即:每個控件按照順序依次排列,若寬度與高度發生變化,控件的排列就會改變),就能很好的快速構建編輯頁面,看看最終用在我的項目中的效果吧,有沒有覺得不錯呢:

這是改變寬度前的布局,有5列,我有紅框標出來了,都是對齊的

這是我縮小寬度后的布局,有2列,我有紅框標出來了,仍然都是對齊的

以上布局效果是不需要編寫任何代碼的,代碼部份僅是設置相應的屬性與方法,如下:

CTextBox控件源碼:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Linq.Expressions;
using Zwj.TEMS.Common;


namespace TEMS.Controls
{
    public partial class CTextBox : UserControl,IZwjDefControl
    {
        [Description("當點擊按鈕時觸發該事件")]
        public event EventHandler OnOpen;

        public CTextBox()
        {
            InitializeComponent();
            this.DispalyOpenButton = false;
        }

        [Browsable(true)]
        [Description("設置文本框的值")]
        public string Value
        {
            get
            {
                return textBox1.Text;
            }
            set
            {
                textBox1.Text = value;
            }
        }

        [Browsable(true)]
        [Description("設置標簽的值")]
        public string Label
        {
            get
            {
                return label1.Text;
            }
            set
            {
                label1.Text = value;
            }
        }

        [Browsable(true)]
        [Description("設置是否顯示打開按鈕")]
        public bool DispalyOpenButton
        {
            get
            {
                return button1.Visible;
            }
            set
            {
                button1.Visible = value;
                textBox1.ReadOnly = button1.Visible;
            }
        }

        [Browsable(true)]
        [Description("設置是否允許多行")]
        public bool AllowMultiline
        {
            get
            {
               return textBox1.Multiline;
            }
            set
            {
                textBox1.Multiline = value;
                if (textBox1.Multiline)
                {
                    textBox1.ScrollBars = ScrollBars.Vertical;
                }
            }
        }

        public void ValueFor<TEntity>(Expression<Func<TEntity, dynamic>> selectField, string fieldValue, bool displayBtn = false, bool allowMultiline=false) where TEntity : class
        {
            var fieldInfo = General.GetPropertyInfo(selectField);
            this.Label = General.GetDisplayName(fieldInfo);
            this.Value = fieldValue;
            this.DispalyOpenButton = displayBtn;
            this.AllowMultiline = allowMultiline;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (this.OnOpen != null)
            {
                this.OnOpen(this, null);
            }
        }
    }
}

  

以下是系統自動生成的源碼:

namespace TEMS.Controls
{
    partial class CTextBox
    {
        /// <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.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
            this.label1 = new System.Windows.Forms.Label();
            this.textBox1 = new System.Windows.Forms.TextBox();
            this.button1 = new System.Windows.Forms.Button();
            this.tableLayoutPanel1.SuspendLayout();
            this.SuspendLayout();
            // 
            // tableLayoutPanel1
            // 
            this.tableLayoutPanel1.ColumnCount = 3;
            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle());
            this.tableLayoutPanel1.Controls.Add(this.label1, 0, 0);
            this.tableLayoutPanel1.Controls.Add(this.textBox1, 1, 0);
            this.tableLayoutPanel1.Controls.Add(this.button1, 2, 0);
            this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
            this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
            this.tableLayoutPanel1.Name = "tableLayoutPanel1";
            this.tableLayoutPanel1.RowCount = 1;
            this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
            this.tableLayoutPanel1.Size = new System.Drawing.Size(250, 40);
            this.tableLayoutPanel1.TabIndex = 0;
            // 
            // label1
            // 
            this.label1.Anchor = System.Windows.Forms.AnchorStyles.Left;
            this.label1.AutoSize = true;
            this.label1.Font = new System.Drawing.Font("微軟雅黑", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.label1.Location = new System.Drawing.Point(3, 10);
            this.label1.Name = "label1";
            this.label1.Size = new System.Drawing.Size(44, 20);
            this.label1.TabIndex = 0;
            this.label1.Text = "label";
            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
            // 
            // textBox1
            // 
            this.textBox1.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom)
                        | System.Windows.Forms.AnchorStyles.Left)
                        | System.Windows.Forms.AnchorStyles.Right)));
            this.textBox1.Font = new System.Drawing.Font("微軟雅黑", 11.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(134)));
            this.textBox1.Location = new System.Drawing.Point(53, 3);
            this.textBox1.Name = "textBox1";
            this.textBox1.Size = new System.Drawing.Size(151, 27);
            this.textBox1.TabIndex = 1;
            // 
            // button1
            // 
            this.button1.Anchor = System.Windows.Forms.AnchorStyles.None;
            this.button1.Location = new System.Drawing.Point(210, 8);
            this.button1.Name = "button1";
            this.button1.Size = new System.Drawing.Size(37, 23);
            this.button1.TabIndex = 2;
            this.button1.Text = "...";
            this.button1.UseVisualStyleBackColor = true;
            this.button1.Click += new System.EventHandler(this.button1_Click);
            // 
            // CTextBox
            // 
            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
            this.Controls.Add(this.tableLayoutPanel1);
            this.Name = "CTextBox";
            this.Size = new System.Drawing.Size(250, 40);
            this.tableLayoutPanel1.ResumeLayout(false);
            this.tableLayoutPanel1.PerformLayout();
            this.ResumeLayout(false);

        }

        #endregion

        private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
        private System.Windows.Forms.Label label1;
        private System.Windows.Forms.TextBox textBox1;
        private System.Windows.Forms.Button button1;
    }
}

 代碼就比較簡單了,在此就不再詳細說明了,只是其中用到了兩個我自定義的方法:

General.GetPropertyInfo ---根據LINQ表達式獲取屬性信息;

General.GetDisplayName ---根據屬性信息獲取顯示的名稱;

方法定義代碼如下(我以前的博文及個人網站www.zuowenjun.cn中也有說明):

        /// <summary>
        /// 獲取屬性需要顯示的名稱
        /// </summary>
        /// <param name="p"></param>
        /// <returns></returns>
        public static string GetDisplayName(PropertyInfo p)
        {
            string displayName = null;
            DisplayAttribute attr = p.GetAttribute<DisplayAttribute>();
            if (attr != null)
            {
                displayName = attr.Name;
            }
            else
            {
                displayName = p.Name;
            }
            return displayName;
        }

        /// <summary>
        /// 獲取指定屬性信息(非String類型存在裝箱與拆箱)
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="select"></param>
        /// <returns></returns>
        public static PropertyInfo GetPropertyInfo<T>(Expression<Func<T, dynamic>> select)
        {
            var body = select.Body;
            if (body.NodeType == ExpressionType.Convert)
            {
                var o = (body as UnaryExpression).Operand;
                return (o as MemberExpression).Member as PropertyInfo;
            }
            else if (body.NodeType == ExpressionType.MemberAccess)
            {
                return (body as MemberExpression).Member as PropertyInfo;
            }
            return null;
        }

如果覺得可以給個推薦吧,如果覺得有不足的地方,歡迎指出,謝謝!

另外為了方便大家學習與使用系列控件,我已將源碼打包上傳,大家可以點以下鏈接下載:

Zwj-Controls.rar


文章列表


不含病毒。www.avast.com
arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()