在寫C#的Winform頁面的時候,常常會遇到下面的問題:ide
一個詳情查看類的頁面,控件是從相關錄入頁面複製來的。爲了讓控件不可編輯,常常要設置控件的Enabled屬性爲False,或ReadOnly屬性爲True(如TextBox)等。但這樣作最大的壞處就是形成了界面風格的不統一,若是字體、字號、風格、顏色都不統一,界面就會顯得很是難看。函數
爲此我設計了一個自定義控件,繼承自TextBox,目的是讓界面風格統一,原型效果以下:字體
(以上兩張原型圖使用Balsamiq繪製)this
我設計的控件MultiFuncViewTextBox代碼以下:spa
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Text.RegularExpressions; using System.Threading.Tasks; using System.Windows.Forms; namespace CustuomControl { public class MultiFuncViewTextBox : TextBox { public MultiFuncViewTextBox() { this.SuspendLayout(); this.ReadOnly = true; this.ResumeLayout(false); } /// <summary> /// 控件是否已初始化 /// </summary> private bool _isInitialized; /// <summary> /// 控件是否已初始化:可設定若是已初始化不容許再次初始化 /// 如不需設定則將set置爲永遠返回false便可 /// </summary> public bool IsInitialized { get { return _isInitialized; } private set { _isInitialized = value; } } /// <summary> /// 控件功能 /// </summary> private FuncType _textFuncType; /// <summary> /// 控件功能:不一樣的功能會對傳入的參數進行不一樣的處理 /// </summary> public FuncType TextFuncType { get { return _textFuncType; } private set { _textFuncType = value; } } /// <summary> /// 初始化時傳入的原始數據 /// </summary> private object _coreValue; /// <summary> /// 初始化時傳入的原始數據 /// </summary> public object CoreValue { get { return _coreValue; } private set { _coreValue = value; } } /// <summary> /// 精度 - 保留小數位數(僅做用於BigChnNum和BigChnCash) /// </summary> private int _precision = 2; /// <summary> /// 精度 - 保留小數位數(僅做用於BigChnNum和BigChnCash) /// </summary> public int Precision { get { return _precision; } set { if (value < 0) { throw new Exception("精度值不能小於0"); } if (value > 10) //可根據項目狀況酌情修改最大容忍精度 { throw new Exception("精度值不能大於10"); } _precision = value; } } /// <summary> /// 是否須要顯示漢字大寫數字(僅做用於BigChnNum和BigChnCash) /// </summary> private bool _needChineseNumerals; /// <summary> /// 是否須要顯示漢字大寫數字(僅做用於BigChnNum和BigChnCash) /// </summary> public bool NeedChineseNumerals { get { return _needChineseNumerals; } set { _needChineseNumerals = value; } } /// <summary> /// 數據字典主項(僅做用於DataDic) /// </summary> private string _dataDicEntry; /// <summary> /// 數據字典主項(僅做用於DataDic) /// </summary> public string DataDicEntry { get { return _dataDicEntry; } set { _dataDicEntry = value; } } private ToolTip toolTip = new ToolTip(); /// <summary> /// 初始化控件 /// </summary> /// <param name="val"></param> /// <param name="funcType"></param> public void InitCoreValue(object val, FuncType funcType) { if (IsInitialized && funcType != TextFuncType) { throw new Exception("不能改變控件用途"); } switch (funcType) { case FuncType.Simple: { this.Text = ""; if (val != null) { this.CoreValue = val; this.TextFuncType = FuncType.Simple; this.Text = val.ToString(); } } break; case FuncType.BigChnNum: { this.Text = ""; if (val is decimal) { this.CoreValue = val; this.TextFuncType = FuncType.BigChnNum; decimal dVal = (decimal)val; this.Text = String.Format("{0:N" + Precision + "}", dVal); if (!IsInitialized && NeedChineseNumerals) { toolTip = new ToolTip();// 氣泡彈窗 toolTip.IsBalloon = false;// 不顯示爲氣泡彈窗,氣泡的箭頭會亂跑 toolTip.SetToolTip(this, ""); toolTip.ShowAlways = true;// 老是顯示 toolTip.UseAnimation = true; toolTip.UseFading = true; this.Enter += (arg, obj) => { try { toolTip.Hide(this); toolTip.Show(RMBToChr2(decimal.Parse(this.Text)), this, 0, -22, 3000); } catch (Exception ex) { MessageBox.Show(ex.Message); } }; this.Leave += (arg, obj) => { try { toolTip.Hide(this); } catch (Exception ex) { MessageBox.Show(ex.Message); } }; } } } break; case FuncType.BigChnCash: { this.Text = ""; if (val is decimal) { this.CoreValue = val; this.TextFuncType = FuncType.BigChnCash; decimal dVal = (decimal)val; this.Text = String.Format("{0:N" + Precision + "}", dVal); if (!IsInitialized && NeedChineseNumerals) { ToolTip toolTip = new ToolTip();// 氣泡彈窗 toolTip.IsBalloon = false;// 不顯示爲氣泡彈窗,氣泡的箭頭會亂跑 toolTip.SetToolTip(this, ""); toolTip.ShowAlways = true;// 老是顯示 toolTip.UseAnimation = true; toolTip.UseFading = true; this.Enter += (arg, obj) => { try { toolTip.Hide(this); toolTip.Show(RMBToChr(decimal.Parse(this.Text)), this, 0, -22, 3000); } catch (Exception ex) { MessageBox.Show(ex.Message); } }; this.Leave += (arg, obj) => { try { toolTip.Hide(this); } catch (Exception ex) { MessageBox.Show(ex.Message); } }; } } } break; case FuncType.Date: { this.Text = ""; DateTime dtVal = new DateTime(); if (val is int || val is long) { this.CoreValue = val; this.TextFuncType = FuncType.Date; dtVal = DateTime.ParseExact(val.ToString(), "yyyyMMdd", null); this.Text = dtVal.ToLongDateString(); } else if (val is DateTime) { this.CoreValue = val; this.TextFuncType = FuncType.Date; dtVal = (DateTime)val; this.Text = dtVal.ToLongDateString(); } } break; case FuncType.Time: { this.Text = ""; DateTime dtVal = new DateTime(); if (val is int || val is long) { this.CoreValue = val; this.TextFuncType = FuncType.Time; dtVal = DateTime.ParseExact(val.ToString(), "HHmmss", null); this.Text = dtVal.ToLongTimeString(); } else if (val is DateTime) { this.CoreValue = val; this.TextFuncType = FuncType.Time; dtVal = (DateTime)val; this.Text = dtVal.ToLongTimeString(); } } break; case FuncType.DataDic: { this.Text = ""; string dicEntry = ""; string subDicEntry = ""; if (val is KeyValuePair<string, string>) { this.CoreValue = val; this.TextFuncType = FuncType.DataDic; KeyValuePair<string, string> pair = (KeyValuePair<string, string>)val; dicEntry = pair.Key; subDicEntry = pair.Value; } else if (val is string) { this.CoreValue = val; this.TextFuncType = FuncType.DataDic; dicEntry = DataDicEntry; subDicEntry = val.ToString(); } if (!string.IsNullOrWhiteSpace(dicEntry) && !string.IsNullOrWhiteSpace(subDicEntry)) { //TODO:獲取對應數據字典值 this.Text = "TODO:獲取對應數據字典值"; } } break; } IsInitialized = true; } public static string RMBToChr(decimal x) { string s = x.ToString("#L#E#D#C#K#E#D#C#J#E#D#C#I#E#D#C#H#E#D#C#G#E#D#C#F#E#D#C#.0B0A"); string d = Regex.Replace(s, @"((?<=-|^)[^1-9]*)|((?'z'0)[0A-E]*((?=[1-9])|(?'-z'(?=[F-L\.]|$))))|((?'b'[F-L])(?'z'0)[0A-L]*((?=[1-9])|(?'-z'(?=[\.]|$))))", "${b}${z}"); return Regex.Replace(d, ".", m => "負元空零壹貳叄肆伍陸柒捌玖空空空空空空空分角拾佰仟萬億兆京垓秭穰"[m.Value[0] - '-'].ToString()); } public static string RMBToChr2(decimal x) { string s = x.ToString("#L#E#D#C#K#E#D#C#J#E#D#C#I#E#D#C#H#E#D#C#G#E#D#C#F#E#D#C#"); string d = Regex.Replace(s, @"((?<=-|^)[^1-9]*)|((?'z'0)[0A-E]*((?=[1-9])|(?'-z'(?=[F-L\.]|$))))|((?'b'[F-L])(?'z'0)[0A-L]*((?=[1-9])|(?'-z'(?=[\.]|$))))", "${b}${z}"); string integerPart = Regex.Replace(d, ".", m => "負元空零壹貳叄肆伍陸柒捌玖空空空空空空空分角拾佰仟萬億兆京垓秭穰"[m.Value[0] - '-'].ToString()); if (integerPart == "") { integerPart = "零"; } string fractionalPart = ""; if (x.ToString().IndexOf('.') != -1) { fractionalPart = x.ToString().Substring(x.ToString().IndexOf('.')); fractionalPart = fractionalPart.Replace(".", "點"); fractionalPart = fractionalPart.Replace("0", "零"); fractionalPart = fractionalPart.Replace("1", "壹"); fractionalPart = fractionalPart.Replace("2", "貳"); fractionalPart = fractionalPart.Replace("3", "叄"); fractionalPart = fractionalPart.Replace("4", "肆"); fractionalPart = fractionalPart.Replace("5", "伍"); fractionalPart = fractionalPart.Replace("6", "陸"); fractionalPart = fractionalPart.Replace("7", "柒"); fractionalPart = fractionalPart.Replace("8", "捌"); fractionalPart = fractionalPart.Replace("9", "玖"); } return integerPart + fractionalPart; } } }
其中FuncType是一個枚舉,包括如下類型:設計
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace CustuomControl { /// <summary> /// 多功能顯示文本框功能類型 /// </summary> public enum FuncType { /// <summary> /// 普通類型 /// </summary> Simple = 0, /// <summary> /// 大寫漢字(普通) /// </summary> BigChnNum = 1, /// <summary> /// 大寫漢字(金額) /// </summary> BigChnCash = 2, /// <summary> /// 日期 /// </summary> Date = 3, /// <summary> /// 時間 /// </summary> Time = 4, /// <summary> /// 數據字典類型 /// </summary> DataDic = 5 } }
上面的控件有以下特色:code
一、控件風格統一。平心而論,詳情查看類頁面只須要顯示結果,不須要放置不少功能性控件(以下拉菜單ComboBox、日期時間選擇控件DateTimePicker等),只須要一個TextBox控件就能夠了。orm
二、CoreValue存儲了用戶存入控件的原始數據,經過控件的Text屬性可取出控件處理後的數據。繼承
三、BigChnNum和BigChnCash兩種控件使用類型,支持Precision(精度)和NeedChineseNumerals(是否須要用氣泡展現漢字大寫金額)。ip
四、若是控件用途設置爲BigChnNum,則氣泡中顯示大寫數字; 若是控件用途設置爲 BigChnCash ,則氣泡中顯示大寫數字金額,並添加單位圓、角、分。
五、若是控件用途設置爲DataDic,可手動設置DataDicEntry屬性,指定數據字典號。
六、初始化統一使用函數InitCoreValue,使用方法爲InitCoreValue(要傳入的數據,控件用途)
public void InitCoreValue(object val, FuncType funcType)
下面用一個例子說明這個控件的用法。
界面控件放置以下:
代碼以下:
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; namespace UserControlTest { public partial class FormMain : Form { public FormMain() { InitializeComponent(); } private void FormMain_Load(object sender, EventArgs e) { try { //查看類界面萬用控件 //通常使用 mfvNormal.InitCoreValue("你好", CustuomControl.FuncType.Simple); //爲數字增長千位符 mfvChnNum.InitCoreValue(123456789.1234M, CustuomControl.FuncType.BigChnNum); mfvChnCash.InitCoreValue(123456789.1234M, CustuomControl.FuncType.BigChnCash); //爲數字增長千位符,並在上方增長漢字大寫氣泡 mfvChnNumWithTip.Precision = 3; mfvChnNumWithTip.NeedChineseNumerals = true; mfvChnNumWithTip.InitCoreValue(123456789.1234M, CustuomControl.FuncType.BigChnNum); mfvChnCashWithTip.Precision = 3; mfvChnCashWithTip.NeedChineseNumerals = true; mfvChnCashWithTip.InitCoreValue(123456789.1234M, CustuomControl.FuncType.BigChnCash); //顯示日期 mfvDate1.InitCoreValue(20160524, CustuomControl.FuncType.Date); mfvDate2.InitCoreValue(20160524L, CustuomControl.FuncType.Date); mfvDate3.InitCoreValue(new DateTime(2016, 5, 24), CustuomControl.FuncType.Date); //顯示時間 mfvTime1.InitCoreValue(140430, CustuomControl.FuncType.Time); mfvTime2.InitCoreValue(140430, CustuomControl.FuncType.Time); mfvTime3.InitCoreValue(new DateTime(2016, 5, 24, 14, 4, 30), CustuomControl.FuncType.Time); //顯示數據字典 mfvDataDic1.InitCoreValue(new KeyValuePair<string, string>("1001", "3"), CustuomControl.FuncType.DataDic); mfvDataDic2.DataDicEntry = "1001"; mfvDataDic2.InitCoreValue("3", CustuomControl.FuncType.DataDic); } catch (Exception ex) { MessageBox.Show(ex.Message); } btnDummy.Select(); //這是一個無用的Button按鈕 } } }
運行效果以下:
END