Winform 在DataGrid中签入Combo
背景
最近看了Winform在DataGrid中怎么嵌入Combo,想到平时项目中写到的一些临时小工具,经常用配置参数,有些配置是简单的地址或文本,有些则是类似1代表SQL,2代表Oracle等。于是想结合刚刚学的知识,做一个示例。
关于参数的保存,想到用数据库,简单点就是用SQLite,可以无需安装数据库,后来想想,干脆用文件进行存储,这样简单,而且.net对Json的支持很好。
资源下载


实现
1.设计数据结构。
public class ListItem
{
public List<ListItem> lstItem = new List<ListItem>();
public string Text { get; set; }
public object Value { get; set; } public ListItem() { }
public ListItem(string pText, string pValue) { Text = pText; Value = pValue; } public override string ToString()
{
return Text;
}
}
Combo Item数据结构
public class ConfigRow
{
public string Name { get; set; }//参数名称
public string Text { get; set; }//参数显示值
public string Value { get; set; }//参数真实值
public string Description { get; set; }//参数描述
public int Type { get; set; }//参数类别 1 常规字符 2 下拉框
public List<ListItem> lstItem { get; set; }//参数下拉框数据源列表
#region 数据源操作
//得到数据源组织的字符串
public string GetItemText()
{
var ret = new StringBuilder();
foreach (var li in lstItem)
{
ret.AppendLine(li.Value + "|" + li.Text);
}
return ret.ToString();
}
//根据格式化字符串设置数据源
public void SetItem(string text)
{
if (lstItem == null)
lstItem = new List<ListItem>();
else
lstItem.Clear();
var arr = text.Trim('\r').Split('\n');
foreach (var a in arr)
{
if (a.Length > )
{
var item = a.Split('|');
if (item.Length > )
{
ListItem li = new ListItem();
li.Value = item[];
li.Text = item[];
lstItem.Add(li);
}
}
}
}
//检查某项是否存在数据源中
public bool CheckItem(string text, string value)
{
var index = lstItem.FindIndex((item) =>
{
return item.Text == text && item.Value.ToString() == value;
});
return index > -;
}
#endregion
}
配置参数实体 数据结构
public class MyConfig
{
#region 公共成员
public ThreadStart ComboChange { get; set; } //下拉框改变事件
public string Path = @"./1.json";//文件保存路径
private List<ConfigRow> lstRow { get; set; } //所有配置行
#endregion #region 私有成员
private ComboBox cbb;
private DataGridView dgv;
private MyConfig() { }
#endregion #region 控件设置与事件
private void Load()
{
#region DataGridView UI
var clName = new System.Windows.Forms.DataGridViewTextBoxColumn();
var clValue = new System.Windows.Forms.DataGridViewTextBoxColumn();
var clDesp = new System.Windows.Forms.DataGridViewTextBoxColumn();
var clType = new System.Windows.Forms.DataGridViewTextBoxColumn();
this.dgv.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] {
clName,
clValue,
clDesp,
clType});
//
// clName
//
clName.DataPropertyName = "Name";
clName.HeaderText = "参数名称";
clName.Name = "clName";
clName.ReadOnly = true;
clName.Width = (int)Math.Floor(dgv.Width * 0.2);
//
// clValue
//
clValue.DataPropertyName = "Text";
clValue.HeaderText = "参数内容";
clValue.Name = "clValue";
clValue.Width = (int)Math.Floor(dgv.Width * 0.3);
//
// clDesp
//
clDesp.DataPropertyName = "Description";
clDesp.HeaderText = "描述";
clDesp.Name = "clDesp";
clDesp.ReadOnly = true;
clDesp.Width = (int)Math.Floor(dgv.Width * 0.5);
//
// clType
//
clType.DataPropertyName = "Type";
clType.HeaderText = "参数状态";
clType.Name = "clType";
clType.ReadOnly = true;
clType.Visible = false;
#endregion
//其他属性设置
cbb = new ComboBox();
cbb.Visible = false;
cbb.DropDownStyle = ComboBoxStyle.DropDownList;
dgv.AutoGenerateColumns = false;//不允许自动创建列
dgv.Controls.Add(cbb);
//绑定数据源
if (lstRow != null && lstRow.Count != ) dgv.DataSource = lstRow;
//注册控件事件
dgv.CurrentCellDirtyStateChanged += CurrentCellDirtyStateChanged;
dgv.CurrentCellChanged += CurrentCellChanged;
dgv.ColumnWidthChanged += ColumnWidthChanged;
cbb.SelectedIndexChanged += SelectedIndexChanged;
dgv.RowPostPaint += RowPostPaint;
}
private void CurrentCellDirtyStateChanged(object sender, EventArgs e)
{
var currentRow = dgv.CurrentRow.DataBoundItem as ConfigRow;
if (currentRow.Type != ) //下拉框类别单元格,在更改下拉框时已修改,此处忽略
{
if (dgv.CurrentCell.Value == null)
currentRow.Value = currentRow.Text = string.Empty;
else
currentRow.Value = currentRow.Text = dgv.CurrentCell.Value.ToString();
}
Update(currentRow);
}
private void CurrentCellChanged(object sender, EventArgs e)
{
if (dgv.CurrentCell == null) return;
//首先清空该事件 否则连续点击2个下拉框执行时有错误
if (ComboChange != null) ComboChange = null;
//若点击的是Value列,而且该参数类别为下拉框
if (dgv.CurrentCell.OwningColumn.Name == "clValue" && dgv.CurrentRow.Cells["clType"].Value.ToString() == "")
{
var current = dgv.CurrentRow.DataBoundItem as ConfigRow;
cbb.DataSource = current.lstItem;
cbb.Text = dgv.CurrentCell.Value.ToString();
//设置下拉框的位置
var rect = dgv.GetCellDisplayRectangle(dgv.CurrentCell.ColumnIndex, dgv.CurrentCell.RowIndex, false);
cbb.Visible = true;
cbb.Bounds = rect;
//注册下拉框事件
ComboChange = new ThreadStart(() =>
{
var li = cbb.SelectedItem as ListItem;
//若值发生变更,则更新DataGridView以及绑定的数据源
if (li.Text != dgv.CurrentCell.Value.ToString())
{
dgv.CurrentCell.Value = li.Text;
current.Text = li.Text;
current.Value = li.Value.ToString();
//这里是引用传递,修改后直接体现在DataBoundItem属性上 无需再次赋值
//dataGridView1.CurrentRow.DataBoundItem = current;
//下拉框直接赋值将不会触发CurrentCellDirtyStateChanged事件 直接更新
Update(current);
}
});
}
else
cbb.Visible = false;
}
private void ColumnWidthChanged(object sender, DataGridViewColumnEventArgs e)
{
dgv.ClearSelection();
cbb.Visible = false;
}
private void RowPostPaint(object sender, DataGridViewRowPostPaintEventArgs e)
{
SolidBrush b = new SolidBrush(dgv.RowHeadersDefaultCellStyle.ForeColor);
e.Graphics.DrawString((e.RowIndex + ).ToString(System.Globalization.CultureInfo.CurrentUICulture),
dgv.DefaultCellStyle.Font, b, e.RowBounds.Location.X + , e.RowBounds.Location.Y + );
}
private void SelectedIndexChanged(object sender, EventArgs e)
{
if (ComboChange != null) ComboChange();
}
#endregion #region 加载文件
//根据路径加载配置文件 并显示在DataGridView控件上
public static MyConfig Load(DataGridView dataGridView1, string path)
{
MyConfig my = new MyConfig();
my.dgv = dataGridView1;
try
{
var json = File.ReadAllText(path);
my.lstRow = JsonConvert.DeserializeObject<List<ConfigRow>>(json);
}
catch
{
my.lstRow = new List<ConfigRow>();
}
my.Load();
return my;
}
//根据路径加载配置文件
public static MyConfig Load(string path)
{
MyConfig my = new MyConfig();
try
{
var json = File.ReadAllText(path);
my.lstRow = JsonConvert.DeserializeObject<List<ConfigRow>>(json);
}
catch
{
my.lstRow = new List<ConfigRow>();
}
return my;
}
//保存
private void Save()
{
if (dgv != null)
{
dgv.DataSource = null;
dgv.DataSource = lstRow;
}
var json = JsonConvert.SerializeObject(lstRow);
File.WriteAllText(Path, json);
}
#endregion #region 增删改查
//增加配置
public void Add(ConfigRow row)
{
var index = lstRow.FindIndex((config) => { return config.Name == row.Name; });
if (index == -) lstRow.Add(row); //找到则更新 未找到则添加
else lstRow[index] = row;
Save();
}
//删除配置
public bool Remove(string name)
{
var index = lstRow.FindIndex((config) => { return config.Name == name; });
if (index == -) return false;
lstRow.RemoveAt(index);
Save();
//删除最后一行时不会出发CurrentCellChanged事件,下拉框可能未被隐藏
if (lstRow.Count == && cbb != null && cbb.Visible) cbb.Visible = false;
return true;
}
//更新配置
public bool Update(ConfigRow row)
{
var index = lstRow.FindIndex((config) => { return config.Name == row.Name; });
if (index == -) return false;
else lstRow[index] = row;
Save();
return true;
}
//查询配置
public ConfigRow Find(string name)
{
return lstRow.Find((config) => { return config.Name == name; });
}
#endregion #region 读取某项的值,并指定默认值
//根据Name读取配置
public string GetString(string name, string defaultValue)
{
var currentRow = Find(name);
if (currentRow == null) return defaultValue;
return currentRow.Value;
}
//根据Name读取配置
public int GetInt(string name, int defaultValue)
{
var currentRow = lstRow.Find((config) => { return config.Name == name; });
if (currentRow == null) return defaultValue;
int value;
if (Int32.TryParse(currentRow.Value, out value))
return value;
return defaultValue;
}
#endregion //测试
public static MyConfig Create(DataGridView dgv)
{
var my = new MyConfig();
my.lstRow = new List<ConfigRow>();
//添加配置项 用户姓名
var row1 = new ConfigRow();
row1.Name = "UserName";
row1.Value = "admin";
row1.Text = "admin";
row1.Description = "配置用户的姓名";
row1.Type = ;//常规字符
my.lstRow.Add(row1); //添加配置项 地址
var row2 = new ConfigRow();
row2.Name = "UserAddress";
row2.Value = "湖南省长沙市";
row2.Text = "湖南省长沙市";
row2.Description = "配置用户的地址";
row2.Type = ;//常规字符
my.lstRow.Add(row2); //添加配置项 性别
var row3 = new ConfigRow();
row3.Name = "UserSex";
row3.Value = "";
row3.Text = "男";
row3.Description = "配置用户的性别";
row3.Type = ;//下拉数据源
//非常规字符必须添加数据源
var item = new ListItem();
item.Text = "男";
item.Value = "";
var item2 = new ListItem();
item2.Text = "女";
item2.Value = "";
row3.lstItem = new List<ListItem>() { item, item2 };
my.lstRow.Add(row3); //添加配置项 年龄
var row4 = new ConfigRow();
row4.Name = "UserAge";
row4.Value = "";
row4.Text = "15岁";
row4.Description = "配置用户的年龄";
row4.Type = ;//下拉数据源
//非常规字符必须添加数据源
row4.lstItem = new List<ListItem>();
for (var i = ; i < ; i++)
{
row4.lstItem.Add(new ListItem(i.ToString() + "岁", i.ToString()));
}
my.lstRow.Add(row4);
return my;
}
}
配置文件结构
2.典型的窗体使用实例
MyConfig my;
public frmMain()
{
InitializeComponent();
} private void Form3_Load(object sender, EventArgs e)
{
my = MyConfig.Load(dataGridView1, "./1.json"); ;
} private void btnAdd_Click(object sender, EventArgs e)
{
frmCreate fc = new frmCreate(my);
if (fc.ShowDialog() == DialogResult.OK)
{
my = fc.my;
}
} private void btnDel_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentCell != null)
{
var name = dataGridView1.CurrentRow.Cells["clName"].Value.ToString();
my.Remove(name);
}
} private void btnUpdate_Click(object sender, EventArgs e)
{
if (dataGridView1.CurrentCell != null)
{
var name = dataGridView1.CurrentRow.Cells["clName"].Value.ToString();
frmCreate fc = new frmCreate(my, name);
if (fc.ShowDialog() == DialogResult.OK)
{
my = fc.my;
}
}
}
使用实例
有些控件列的操作和一些必需的属性设置,把这些代码从Designer.cs中拷贝出来,直接放在方法里直接调用,是为了避免新建一个窗体,又有重复那么多设置操作。但这样肯定会带来一定的不灵活性。
就这样做了2天,做完发现实用性有限,权当技术研究吧。
另外还可以配置参数实体上添加正则属性,这样就方便进行正则检查参数是否合法。
Winform 在DataGrid中签入Combo的更多相关文章
- winform中DataGrid控件的宽度设置
最近修改一个win5.0的PDA程式,碰到一个问题.就是给DataGrid控件绑定数据的时候,这个控件的宽度不能调整,有时候数据较长,就显示不全.然后想在程式里自定义它的宽度,设置不成功.然后网上没找 ...
- winform窗体间利用委托传值(一)
前台:在winform窗体Form1放入pictureBox1 后台代码: namespace 点击小图变成大图 { public delegate void ClickDelegateHander( ...
- 【转】VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)
原文网址:http://www.jizhuomi.com/software/189.html 上一节鸡啄米讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常 ...
- VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)
上一节鸡啄米讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常见,例如,在Windows系统的控制面板上设置语言或位置时,有很多选项,用来进行选择的控件就是 ...
- 第一个C# Winform实例
前面我们准备好了相关的库,现在开始搭建环境,本人自动化行业,就用Windorm开发吧,例子仅仅做引导,希望大家能深入.VS版本VS2017 1:打开VS建立一个WInform 项目.拉入两个控件,gr ...
- winform 自定义控件(高手)
高手推荐:https://www.cnblogs.com/bfyx/p/11364884.html c#Winform自定义控件-目录 前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件 ...
- VS2010-MFC(常用控件:组合框控件Combo Box)
转自:http://www.jizhuomi.com/software/189.html 上一节讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常见,例如, ...
- WPF DataGrid 复合表头 (实现表头合并,自定义表头)
功能说明: 将 DataGrid嵌套在本控件内,使用Label自定义表头,如果需要上下左右滚动 需要在控件外围添加 ScrollViewer 并且设置 ScrollVisibility 为Auto ...
- CYQ.Data V5 分布式缓存Redis应用开发及实现算法原理介绍
前言: 自从CYQ.Data框架出了数据库读写分离.分布式缓存MemCache.自动缓存等大功能之后,就进入了频繁的细节打磨优化阶段. 从以下的更新列表就可以看出来了,3个月更新了100条次功能: 3 ...
随机推荐
- 笔记-docker-2安装(centos6.5环境)
笔记-docker-2安装(centos6.5环境) 1. centos6.5安装docker 1.1. 升级内核 安装docker,官方文档要求linux kernel至少3.8以上 ...
- LoadRunner使用代理远程执行提示找不到“pre_cci.c”文件
好久没有使用LoadRunner了,工作需要使用一下,执行总是提示找不到“pre_cci.c”文件,找问题花了很长时间终于找到问题了.万事还是需要找到原因: cci 会将 pre_cci.c 文件作为 ...
- 6 Django的视图层
视图函数 一个视图函数,简称视图,是一个简单的Python 函数,它接受Web请求并且返回Web响应.响应可以是一张网页的HTML内容,一个重定向,一个404错误,一个XML文档,或者一张图片. . ...
- HTML介绍和head标签-01
主要内容 web标准 浏览器介绍 开发工具介绍 HTML介绍 HTML颜色介绍 HTML规范 HTML结构详解 一.web标准 web准备介绍: w3c:万维网联盟组织,用来制定web标准的机构(组织 ...
- 3611: [Heoi2014]大工程
3611: [Heoi2014]大工程 链接 分析: 树形dp+虚树. 首先建立虚树,在虚树上dp. dp:sum[i]为i的子树中所有询问点之间的和.siz[i]为i的子树中有多少询问点,mn[i] ...
- 1196/P2323: [HNOI2006]公路修建问题
1196: [HNOI2006]公路修建问题 Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 2191 Solved: 1258 Descriptio ...
- border与background定位
1.background定位的局限 只能相对于左上角数值定位,不能相对于右下 即background-position默认相对于左上方定位的 2.怎样让图片相对于右下角? background-pos ...
- 《Cracking the Coding Interview》——第18章:难题——题目10
2014-04-29 04:22 题目:给定一堆长度都相等的单词,和起点.终点两个单词,请从这堆单词中寻找一条变换路径,把起点词变成终点词,要求每次变换只能改一个字母. 解法:Leetcode中有Wo ...
- 《Cracking the Coding Interview》——第8章:面向对象设计——题目9
2014-04-23 23:57 题目:如何设计一个内存文件系统,如果可以的话,附上一些代码示例. 解法:很遗憾,对我来说不可以.完全没有相关经验,所以实在无从入手.这题目应该和工作经验相关吧? 代码 ...
- 二分法求函数值的Pascal实现
用二分法求在(a,b)上单调的函数近似值 第八行的表达式可更改,第三行的kexi决定的精度,小数值计算可将第五行的extended更为real或double PROGRAM EQUANTION ( ...