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 ...
随机推荐
- poj1182食物链
Description 动物王国中有三类动物A,B,C,这三类动物的食物链构成了有趣的环形.A吃B, B吃C,C吃A. 现有N个动物,以1-N编号.每个动物都是A,B,C中的一种,但是我们并不知道它到 ...
- javascript的js调用
本来从一开始接触编程开始,自己就一直写后端,但是对于前端真的不会,但是没办法呀,公司要做,所以,好吧,开始了写一写简单的javascript的内容其中,在xxx.jsp页面中出现了这个 <a c ...
- Lambda与LINQ
Lambda与LINQ写法对比: 上为Lambda 下为LINQ 显示指定列 Students.select(u=>(new {Name=u.Sname,Address=u.Saddress}) ...
- 遍历两个自定义列表来实现字典(key:value)
#自定义key ${keys} create list key1 key2 key3 #自定义value ${values} create list v ...
- django文件上传、图片验证码、抽屉数据库设计
1.Django文件上传之Form方式 settings.py, ALLOWED_HOSTS = ['*'] INSTALLED_APPS = [ 'django.contrib.admin', 'd ...
- HDU 4741 Save Labman No.004 ( 三维计算几何 空间异面直线距离 )
空间异面直线的距离直接套模板. 求交点:求出两条直线的公共法向量,其中一条直线与法向量构成的平面 与 另一条直线 的交点即可.还是套模板o(╯□╰)o 1.不会有两条线平行的情况. 2.两条直线可能相 ...
- 后端model传入前端JSP页面中的值判断后再取值
所遇到的问题后端model传入前端JSP页面中的值通过foreach循环内要满足条件才能取值给Div中,我们知道jsp页面中可以直接用EL表达式取值,格式就是${"model中传来的数据&q ...
- Nginx简单的配置详情
大致了解Nginx后,直接从配置文件入手: [shell] #定义Nginx运行的用户和用户组 user nginx; #nginx进程数,建议设置为等于CPU总核心数. worker_process ...
- mysql备份策略
1.备份的种类 完全备份,就是备份整个数据库对象 事务日志备份, 备份事务日志记录上一次的数据库改变 增量备份,也叫差异备份 文件备份 2.备份方式 逻辑备份, 既备份sql语句,使用mysql自带的 ...
- mac系统安装/升级node
一.安装 1.node 是通过brew来安装的,所以第一步先安装brew ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Ho ...