背景

  最近看了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的更多相关文章

  1. winform中DataGrid控件的宽度设置

    最近修改一个win5.0的PDA程式,碰到一个问题.就是给DataGrid控件绑定数据的时候,这个控件的宽度不能调整,有时候数据较长,就显示不全.然后想在程式里自定义它的宽度,设置不成功.然后网上没找 ...

  2. winform窗体间利用委托传值(一)

    前台:在winform窗体Form1放入pictureBox1 后台代码: namespace 点击小图变成大图 { public delegate void ClickDelegateHander( ...

  3. 【转】VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)

    原文网址:http://www.jizhuomi.com/software/189.html 上一节鸡啄米讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常 ...

  4. VS2010/MFC编程入门之二十五(常用控件:组合框控件Combo Box)

    上一节鸡啄米讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常见,例如,在Windows系统的控制面板上设置语言或位置时,有很多选项,用来进行选择的控件就是 ...

  5. 第一个C# Winform实例

    前面我们准备好了相关的库,现在开始搭建环境,本人自动化行业,就用Windorm开发吧,例子仅仅做引导,希望大家能深入.VS版本VS2017 1:打开VS建立一个WInform 项目.拉入两个控件,gr ...

  6. winform 自定义控件(高手)

    高手推荐:https://www.cnblogs.com/bfyx/p/11364884.html   c#Winform自定义控件-目录   前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件 ...

  7. VS2010-MFC(常用控件:组合框控件Combo Box)

    转自:http://www.jizhuomi.com/software/189.html 上一节讲了列表框控件ListBox的使用,本节主要讲解组合框控件Combo Box.组合框同样相当常见,例如, ...

  8. WPF DataGrid 复合表头 (实现表头合并,自定义表头)

    功能说明: 将 DataGrid嵌套在本控件内,使用Label自定义表头,如果需要上下左右滚动 需要在控件外围添加  ScrollViewer 并且设置  ScrollVisibility 为Auto ...

  9. CYQ.Data V5 分布式缓存Redis应用开发及实现算法原理介绍

    前言: 自从CYQ.Data框架出了数据库读写分离.分布式缓存MemCache.自动缓存等大功能之后,就进入了频繁的细节打磨优化阶段. 从以下的更新列表就可以看出来了,3个月更新了100条次功能: 3 ...

随机推荐

  1. .c和.h区别

    本质没有区别: .h是头文件 一般情况下下边内容放在.h文件中 宏定义 结构体,联合,枚举声明 typedef声明 外部函数声明 全局变量声明 .c是程序文件 一般情况下下边内容放在.h文件中 内含函 ...

  2. hive-pom.xml

    4.0.0 <groupId>com.cenzhongman</groupId> <artifactId>hive</artifactId> <v ...

  3. 全方位认识HDMI接口技术

    HDMI接口并不是一个开放的标准.制造商必须向HDMI标准制定协会支付版税,来换取一个生产许可证.不过这个版税可不便宜,每年要交纳15000美元的许可费,并且更黑的是每生产一个HDMI接口就要支付0. ...

  4. videomon 环境搭建

    1.安装ACE-5.8.0.tar.bz2 tar -zxvf ACE-.tar.bz2 cd ACE_wrappers/mkdir buildcd build../configuremake &am ...

  5. 了解JavaScript核心精髓(四)

    ES6 1.import与require区别 import 是同步导入js模块. require 是异步导入js模块. 2.使用let与const let con1 = 3 //与var作用相似,le ...

  6. ADB命令总结(1)

    今日继续学习ADB,使用真机来操作,因此把所用到的命令总结如下: 一,模拟按HOME键 adb shell input keyevent KEYCODE_HOME 二,滑动手机屏幕 从(x1,y1)滑 ...

  7. Python学习-前台开发-ajax操作

    概述 对于WEB应用程序:用户浏览器发送请求,服务器接收并处理请求,然后返回结果,往往返回就是字符串(HTML),浏览器将字符串(HTML)渲染并显示浏览器上. 1.传统的Web应用 一个简单操作需要 ...

  8. AppCan试用体验

    最近自己想开发一个基于Android平台的小应用,但不想使用JAVA开发,还要快速实现功能,学习成本低. 所以找了很多框架,最后基本锁定在phoneGap和AppCan,又看了AppCan与phone ...

  9. Python——数据类型之list、tuple

    本篇主要内容 •  list初识 •  list元素的访问 •  list内部所有的方法 •  tuple介绍和与list用法的比较 我觉得Python里面用的最多的就是List了,感觉好强大.他能存 ...

  10. Java面试准备十六:数据库——MySQL性能优化

    2017年04月20日 13:09:43 阅读数:6837 这里只是为了记录,由于自身水平实在不怎么样,难免错误百出,有错的地方还望大家多多指出,谢谢. 来自MySQL性能优化的最佳20+经验 为查询 ...