最近遇到了一个场景,就是在数据库中没有数据字典的情况下,由C#程序临时维护一组类似数据字典功能的类。功能是可以通过键取出值,通过值取出对应的键(仅取第一个匹配的键),类要求具备一定的可扩展性,可以对一些控件(如ComboBox)进行数据源的初始化。因此我自己设计了一个模式,用于实现这个功能。
1、准备工作
建立一个Windows窗体应用程序,程序集名为DataDictTest,里面包含窗体FormMain
窗体FormMain中包括一个下拉菜单ComboBox,一个放置在DataGridView中的下拉菜单列,控件摆放如下:
建立一个ComboBox取名cmbWeek
建立一个DataGridView取名dgvTest,添加下拉菜单类型的列,取名colWeek
2、建立键值对照基类DataDict
键值对照基类DataDict,包括三个字段(字典号码DicCode、字典名称DicName、字典备注DicRemark),还有一个数据源DataDic用于保存这些键值对,DataDic包含两列:KEY和TEXT,在键值对照中,KEY的值保存了程序需要识别的值,类似数据字典中某个数据字典项的键;TEXT的值保存给用户真正看到的文字描述,类似于数据字典项中的值。在基类中,可以提供一些用于初始化具体控件的数据源的函数,如下面代码中实现了InitComboBox、InitDataGridViewComboBoxColumn等函数,用于初始化ComboBox控件和DataGridViewComboBoxColumn数据列的数据。
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DataDictTest
{
/// <summary>
/// 键值对照基类
/// </summary>
class DataDict
{
/// <summary>
/// 获取数据字典项
/// </summary>
/// <returns></returns>
private DataTable GetDataDic()
{
DataTable dt = new DataTable(DicName);
dt.Columns.Add("KEY"); //数据字典子项 - 标识字符
dt.Columns.Add("TEXT"); //数据字典子项 - 汉字描述
return dt;
}
/// <summary>
/// 键值对照基类
/// </summary>
public DataDict()
{
//数据字典号码
_dicCode = "";
//数据字典名称
_dicName = "";
//数据字典备注
_dicRemark = "";
_dataDic = GetDataDic();
}
/// <summary>
/// 数据字典号码
/// </summary>
protected string _dicCode;
/// <summary>
/// 数据字典号码
/// </summary>
public string DicCode
{
get
{
return _dicCode;
}
}
/// <summary>
/// 数据字典名称(英文标识符)
/// </summary>
protected string _dicName;
/// <summary>
/// 数据字典名称(英文标识符)
/// </summary>
public string DicName
{
get
{
return _dicName;
}
}
/// <summary>
/// 数据字典备注
/// </summary>
protected string _dicRemark;
/// <summary>
/// 数据字典备注
/// </summary>
public string DicRemark
{
get
{
return _dicRemark;
}
}
/// <summary>
/// 数据字典内数据
/// </summary>
protected DataTable _dataDic;
/// <summary>
/// 数据字典内数据
/// </summary>
public DataTable DataDic
{
get
{
return _dataDic;
}
}
/// <summary>
/// 初始化控件数据源:ComboBox
/// </summary>
/// <param name="cmb"></param>
public void InitComboBox(ComboBox cmb)
{
if (cmb == null)
{
throw new Exception("非法输入:输入ComboBox为空");
}
cmb.Items.Clear();
var value = from x in _dataDic.AsEnumerable() select x["TEXT"].ToString();
cmb.Items.AddRange(value.ToArray());
}
/// <summary>
/// 初始化控件数据源:DataGridViewComboBoxColumn
/// </summary>
/// <param name="cmb"></param>
public void InitDataGridViewComboBoxColumn(DataGridViewComboBoxColumn cmb)
{
if (cmb == null)
{
throw new Exception("非法输入:输入ComboBox为空");
}
cmb.Items.Clear();
var value = from x in _dataDic.AsEnumerable() select x["TEXT"].ToString();
cmb.Items.AddRange(value.ToArray());
}
/// <summary>
/// 根据字典键获取字典值
/// </summary>
/// <param name="key"></param>
/// <returns></returns>
public string GetText(string key)
{
var value =
from x in _dataDic.AsEnumerable()
where x["KEY"].ToString().Trim() == key.Trim()
select x["TEXT"].ToString().Trim();
return value.Count() > 0 ? value.First() : default(string);
}
/// <summary>
/// 根据字典值获取匹配的第一个键
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public string GetKey(string text)
{
var value =
from x in _dataDic.AsEnumerable()
where x["TEXT"].ToString().Trim() == text.Trim()
select x["KEY"].ToString().Trim();
return value.Count() > 0 ? value.First() : default(string);
}
}
}
3、实现具体的数据键值对照类
有了基类,就可以实现具体的子类对基类继承,通过设置不同的KEY-TEXT对,完成不同的键值对照类。如下面这个类DictWeek,存储了一周七天的数据键值对照:
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace DataDictTest
{
/// <summary>
/// 数据字典:会计年度
/// </summary>
internal class DictWeek : DataDict
{
/// <summary>
/// 获取数据字典项
/// </summary>
/// <returns></returns>
private DataTable GetDataDic()
{
DataTable dt = new DataTable(DicName);
dt.Columns.Add("KEY"); //数据字典子项 - 标识字符
dt.Columns.Add("TEXT"); //数据字典子项 - 汉字描述
/* ↓↓↓↓这里输入数据字典项↓↓↓↓ */
dt.Rows.Add("0", "星期日");
dt.Rows.Add("1", "星期一");
dt.Rows.Add("2", "星期二");
dt.Rows.Add("3", "星期三");
dt.Rows.Add("4", "星期四");
dt.Rows.Add("5", "星期五");
dt.Rows.Add("6", "星期六");
/* ↑↑↑↑这里输入数据字典项↑↑↑↑ */
return dt;
}
/// <summary>
/// 星期对照
/// </summary>
public DictWeek()
: base()
{
//数据字典号码
_dicCode = "";
//数据字典名称
_dicName = "";
//数据字典备注
_dicRemark = "";
_dataDic = GetDataDic();
}
}
}
在每个子类中的构造函数中设置数据字典的号码、名称、备注,并在GetDataDic函数中设置键值对照项。
4、实际应用
在FormMain中初始化数据字典:
DictWeek dictWeek = new DictWeek();
并在Load函数中对控件的数据源进行初始化
dictWeek.InitComboBox(cmbWeek);
dictWeek.InitDataGridViewComboBoxColumn(
dgvTest.Columns["colWeek"] as DataGridViewComboBoxColumn);
在实际调用数据字典时,无论取出的是键或值,都可以调用键值对照类中的对应函数(GetText、GetKey)取到另一半。FormMain中完整的C#代码如下:
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 DataDictTest
{
public partial class FormMain : Form
{
public FormMain()
{
InitializeComponent();
}
/// <summary>
/// 数据字典:星期
/// </summary>
DictWeek dictWeek = new DictWeek();
/// <summary>
/// Load函数
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void FormMain_Load(object sender, EventArgs e)
{
//ComboBox中添加字典数据
dictWeek.InitComboBox(cmbWeek);
//DataGridView中的下拉菜单列,添加字典数据
dictWeek.InitDataGridViewComboBoxColumn(
dgvTest.Columns["colWeek"] as DataGridViewComboBoxColumn);
}
/// <summary>
/// ComboBox:cmbWeek 值发生变化时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void cmbWeek_SelectedIndexChanged(object sender, EventArgs e)
{
string text = cmbWeek.Text;
string s = string.Format("KEY: {0}; TEXT: {1}.", dictWeek.GetKey(text), text);
MessageBox.Show(s);
}
/// <summary>
/// DataGridView:dgvTest 值发生变化时触发
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void dgvTest_CellValueChanged(object sender, DataGridViewCellEventArgs e)
{
//下拉菜单列不存在时,不进行后续操作
if (!dgvTest.Columns.Contains("colWeek"))
{
return;
}
//仅下拉菜单列内容发送变化时,显示数据取值情况
if (e.ColumnIndex == dgvTest.Columns["colWeek"].Index)
{
string text = dgvTest.Rows[e.RowIndex].Cells[e.ColumnIndex].Value.ToString();
string s = string.Format("KEY: {0}; TEXT: {1}.", dictWeek.GetKey(text), text);
MessageBox.Show(s);
}
}
}
}
5、应用效果
ComboBox的下拉菜单效果
下拉菜单取值后,获得选择的键和值:
DataGridView中的下拉菜单列效果:
下拉菜单列取值后,在该单元格退出编辑状态后显示选中项的键和值:
END