2、DataGridView样式设置:不可编辑、自动填充、中文列标题、交替行
根据上一课的基本信息管理主界面,需要实现的效果是点击每个图片按钮可以查看相应的信息,也就是在这些按钮的点击事件中添加数据绑定。
先来实现点击上面按钮后能绑定数据到DataGridView中
1、DataGridView的数据绑定(部门信息按钮的点击事件)
(1)给本界面的cs文件添加using引用
using System.Data.SqlClient;
using NorthwindDAL;
(2)为datagridView添加数据源属性
DataSet ds= SqlHelper.ExecuteDataset(SqlHelper.GetConnSting(),CommandType.Text,"SELECT * FROM 部门表");
dataGridView.DataSource = ds.Tables[0];
绑定完成后,为了保证测试方便,我们到Program.cs文件中临时更改一下启动窗体,将原来的Login改为基本信息管理主界面。
运行一下就能看到现在的界面,点击信息部门按钮看看是否能加载部门表。
其他按钮的表格绑定以此类推。
我们发现了几个问题:
1) 部门信息是可以任意编辑但是不影响数据库。能否让这个控件不能编辑?
2) 部门信息的数据列比较少,能否自动填充整个窗体?
3) 雇员信息的列标题是英文,能否翻译成中文?
4) 雇员信息字段很多,需要拉动水平滚动条才能看完,能否只显示关键的列?
5) 客户信息记录很多,容易看错行,能否设置交错行?
6) 产品类别的描述字段内容很多,能否完全显示?
这些都是对datagridView的样式要求啦,一起来看看怎么定制这个控件的效果。
1) 部门信息是可以任意编辑但是不影响数据库。能否让这个控件不能编辑?
回到设计界面,对控件属性进行相应的设置
AllowUserToAddRows——是否允许用户自动增加新行
EditMode——EditProgrammatically,只允许从代码进行编辑
ReadOnly——只读模式
注意:对datagridView控件的设置是会影响所有加载到这个控件的数据的。
2) 部门信息的数据列比较少,能否自动填充整个窗体?
控件的属性设置可以放在代码内完成,只要点击过这个按钮,所有的按钮显示数据都会记住这个属性,因此可以在设计界面中设置自动填充,如果有特殊要求的再到代码中设置
比如设置了行高自动调整,则产品类别中显示效果
但是与此同时,雇员的显示效果就很差
这时可以在雇员信息的点击按钮内加上列宽的设置
dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells;
列宽与行高的设置请参考延伸知识。注意关于性能:
通过 AutoSizeColumnsMode 或者 AutoSizeRowsMode 属性所指定的单元格进行自动调整时,如果调整次数过多那么将可能导致性能下降,尤其是在行和列数比较多的情况下。在这时用 DisplayedCells 代替 AllCells 能减少非所见的单元格的调整,从而提高性能。
3) 雇员信息的表头是英文,能否翻译成中文?
方法一:用SQL语句转换,也就是说SELECT Name as 姓名 FROM ……
方法二:循环设置所有的列标题
方法三:直接用中文名作数据库的字段名吧,一劳永逸
4) 雇员信息字段很多,需要拉动水平滚动条才能看完,能否只显示关键的列?
方法一:还是SQL语句的问题,这个自己考虑
方法二:把已经显示出来的列隐藏掉,对于代码是可用的,但对用户是不可见的
注意:这里的[]内使用的是数据库中的字段名称,不是刚刚的中文列标题
5) 客户信息记录很多,容易看错行,能否设置交错行?可否设置选中行样式?
6) 产品类别的图片能否完全显示?
其实刚刚已经讲了,还记得吗?设置什么?
延伸知识:内容填充
l 根据内容自动填充——部门信息
DataGridViewAutoSizeColumnsMode成员名称 | 说明 |
AllCells | 列宽调整到适合列中所有单元格(包括标头单元格)的内容。 |
AllCellsExceptHeader | 列宽调整到适合列中除标头单元格以外所有单元格内容。 |
ColumnHeader | 列宽调整到适合列标头单元格的内容。 |
DisplayedCells | 列宽调整到适合位于屏幕上当前显示的行中的列的所有单元格(包括标头单元格)的内容。 |
DisplayedCellsExceptHeader | 列宽调整到适合位于屏幕上当前显示的列中的列的所有单元格(不包括标头单元格)的内容。 |
Fill | 列宽调整到使所有列宽精确填充控件的显示区域,要求使用水平滚动的目的只是保持列宽大于DataGridViewColumn.MinimumWidth属性的值。相对列宽由相对 DataGridViewColumn.FillWeight属性值决定。 |
None | 列宽不会自动调整。 |
行高的自动调整
DataGridView行的高度自动调整,可以使用DataGridView1.AutoSizeRowsMode属性实现。
//根据Header和所有单元格的内容自动调整行的高度
DataGridView1.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCells;
DataGridViewAutoSizeRowsMode枚举的成员如下所示:
DataGridViewAutoSizeRowsMode成员名称 | 说明 |
AllCells | 将行高调整到适合行中所有单元格(包括标头单元格)的内容。 |
AllCellsExceptHeaders | 将行高调整到适合行中所有单元格(不包括标头单元格)的内容。 |
AllHeaders | 将行高调整到适合行标头的内容。 |
DisplayedCells | 将行高调整到适合屏幕上当前显示的行中所有单元格(包括标头单元格)的内容。 |
DisplayedCellsExceptHeaders | 将行高调整到适合屏幕上当前显示的行中所有单元格(不包括标头单元格)的内容。 |
DisplayedHeaders | 将行高调整到适合屏幕上当前显示的行标头的内容。 |
None | 行高不自动调整。 |
好了,到目前为止,我们已经可以比较专业的显示出数据库的数据。以雇员信息表按钮有例,他的设置代码如下:
//后续按钮事件依次类推 private void btn雇员信息_Click(object sender, EventArgs e) { //利用Sqlhelper类绑定数据源 DataSet ds = SqlHelper.ExecuteDataset(SqlHelper.GetConnSting(), CommandType.Text, "SELECT * FROM Employees"); dataGridView.DataSource = ds.Tables[0]; //雇员信息的列标题改中文名 string strFieldText = "雇员编号,所在部门,密码,姓名,头衔职务,称呼,出生日期,雇佣日期,地址,城市,地区,邮编,国家,家庭电话,扩展,照片,备注,负责人,照片地址"; string[] arrFieldText = strFieldText.Split(','); for (int i = 0; i < dataGridView.Columns.Count; i++) dataGridView.Columns[i].HeaderText = arrFieldText[i]; //不显示某些列,只显示关键列 dataGridView.Columns["Password"].Visible = false; dataGridView.Columns["TitleOfCourtesy"].Visible = false; dataGridView.Columns["Address"].Visible = false; dataGridView.Columns["Extension"].Visible = false; dataGridView.Columns["Notes"].Visible = false; dataGridView.Columns["PhotoPath"].Visible = false; //dataGridView.Columns["Photo"].Visible = false; //设置列宽的显示 dataGridView.AutoSizeRowsMode = DataGridViewAutoSizeRowsMode.AllCellsExceptHeaders; dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.DisplayedCells; }
下一步是增加部门信息了。
请大家先设计一个新增部门信息的窗体,注意属性与控件类型。
难点:弹出新窗口、自动生成最大的编号、部门经理的下拉列表,保存到数据库
(1) 点击新增按钮后弹出新增部门信息的窗体
跟上次一样,申明一个新的窗体对象后,使用show的方法即可。
Form 新增部门信息= new新增部门信息();
新增部门信息.Show();
我们不满足于此,我们需要能找到当前数据库中的最大编号,然后递增1作为新部门的编号出现在新窗体,且这个编号是用户不能手动修改。
在新窗体中,我们写个方法GenerateNew部门编号吧,然后调用这个方法,将值返回给tbx部门编号。
/// <summary> /// 先取得数据库内最大的部门编号,递增1后作为新部门的编号 /// </summary> /// <returns>返回新部门编号</returns> public static string GenerateNew部门编号() { //获得数据库中最大的部门编号 string strMax部门编号 = (string)SqlHelper.ExecuteScalar(SqlHelper.GetConnSting(), CommandType.Text, "SELECT 部门编号 FROM 部门表 ORDER BY 部门编号 DESC"); //给部门最大编号加1,这里需要使用到字符串处理函数——取出子串 int 部门编号 = Convert.ToInt32(strMax部门编号.Substring(2)) + 1; //返回这个编号,这里还需要判断一下,如果你的编号是int型的就不需要判断直接返回 if (部门编号 >= 100) { return "BM" + 部门编号; } else if (部门编号 >= 10) { return "BM0" + 部门编号; } else { return "BM00" + 部门编号; } }
private void 新增部门信息_Load(object sender, EventArgs e) { //为comboBox添加数据源 string strSql = "SELECT FirstName FROM Employees"; DataSet ds = SqlHelper.ExecuteDataset(SqlHelper.GetConnection(), CommandType.Text, strSql); cbx部门经理.DataSource = ds.Tables[0]; cbx部门经理.DisplayMember = "FirstName"; cbx部门经理.ValueMember = "FirstName"; }
延伸知识:下拉列表控件——ComboBox的常用属性设置
1)Text属性:获取当前显示的文本
2)SelectedText属性:获得当前选中的文本(控件获得光标且DropDown属性不为DropDownList)
注意:但应注意,所选内容会因用户交互而自动更改。如Button的Click事件中,SelectedIndexChanged 或 SelectedValueChanged 事件中,此属性会返回空字符串(参见MSCN:http://msdn.microsoft.com/zh-cn/partners/system.windows.forms.combobox.selectedtext(VS.90).aspx )
3)SelectedValue属性:当前显示项对应的Value值(仅在绑定数据源时,设置了ValueMember时才可以用)
4)SelectedItem属性:控件当前选中项
5)SelectedIndex属性:当前选中项的索引
有了Sqlhelper啥也不用愁了,只需要准备参数就可以了,这回我们使用的是sqlhelper中ExecuterNonQuery的方法。大家尽量自己先写写,再对照代码。
请大家根据数据库表结构设计一个新增雇员的界面
与新增部门信息不同的是:为了能否上传雇员招聘,我们还需要拖入一个OpenfileDiaLog控件
这个窗体内的雇员编号、所在部门、新增按钮事件跟前面的新增部门信息是一样,请大家自行完成。
问题接二连三的出现了:
1、 现在的新增按钮总是弹出的是新增部门信息,怎么能根据datagridView的内容弹出相应的窗体呢?
2、 这个图片如何操作?如果保存到数据?
请先百度看看或者根据下面的延伸知识能否解决这两个问题,解决办法将于下一课公布。
Windows 窗体的 OpenFileDialog(打开文件对话框)组件是一个预先配置的对话框。它与 Windows 操作系统的“打开文件”对话框相同。该控件是从 CommonDialog 类继承的。
在基于 Windows 的应用程序中,可该组件实现简单的文件选择,而不必配置自己的对话框。利用标准的 Windows 对话框,可以创建用户所熟悉的应用程序界面。
OpenFileDialog 组件的主要属性包括:
(1) Title 属性:获取或设置文件对话框标题。默认值为空字符串("")。
如果标题为空字符串,系统将使用默认标题“打开”。
(2) Multiselect 属性:获取或设置一个值,该值指示对话框是否允许选择多个文件。
如果对话框允许同时选定多个文件,则为 true;反之,则为 false。默认值为 false。使用 FileNames 属性可访问选定文件名的完整列表。
(3) ShowReadOnly 属性:获取或设置一个值,该值指示对话框是否包含只读复选框。
如果对话框包含只读复选框,则为 true;否则为 false。默认值为 false。
(4) ReadOnlyChecked 属性:获取或设置一个值,该值指示是否选定只读复选框。
如果选中了只读复选框,则为 true;反之,则为 false。默认值为 false。
(5) Filter 属性:获取或设置当前文件名过滤字符串,该字符串决定对话框的“文件类型”框中出现的选择内容。
对于每个过滤选项,过滤字符串都包含过滤条件说明,后接一垂直线条(|)和过滤模式。不同过滤选项的字符串由垂直线条隔开。例如:
"Text files (*.txt)|*.txt|All files (*.*)|*.*"
如果要将多个过滤模式添加到过滤条件中,可用分号将文件类型分隔开,例如:
"Image Files(*.BMP;*.JPG;*.GIF)|*.BMP;*.JPG;*.GIF|All files (*.*)|*.*"
使用 FilterIndex 属性设置第一个显示给用户的过滤选项。
(6) FilterIndex 属性:获取或设置文件对话框中当前选定过滤条件的索引。
默认值为 1。第一个过滤条目的索引值为 1。
(7) FileName 属性:获取或设置一个包含在文件对话框中选定的文件名的字符串。也就是在对话框中选择的文件名,默认值为空字符串("")。
文件名既包含文件路径也包含扩展名。如果未选定文件,将返回空字符串。
(8) FileNames 属性:获取对话框中所有选定文件的文件名。
属性值是一个 String 类型数组。每个文件名都既包含文件路径又包含文件扩展名。如果未选定文件,该方法将返回空数组。
该组件的主要方法包括:
(1) ShowDialog 方法:在运行时显示对话框。
(2) OpenFile 方法:打开用户选定的具有只读权限的文件,该文件由 FileName 属性指定。
使用该方法可从对话框以只读方式快速打开文件。
方法一:在数据库中添加图片名字,然后把图片存在指定的文件夹中。
这种方法存起来简单,但是删除的时候麻烦。
存:在数据库中建一个文本字段(access)或者varchar字段(sqlserver)长度能放上一张图片即可
过程:就是一般的存的insert into
举个例子:sql数据库中有一个id字段 自增类型 一个name字段,用于存放图片名称的类型是varchar类型。这winform界面中你可以拖动一个TextBox,用于存放路径,一个Button这个就不说了,还有一个openFileDialog
if (this.openFileDialog1.ShowDialog() == DialogResult.OK) { this.textBox1.Text = openFileDialog1.FileName; } //打开路径,必不可少的 这些都是是在button单击事件里完成的 if (openFileDialog1.FileName.Length > 0) // 判断openFileDialog1路径的长度 { string oldName = openFileDialog1.FileName; //定义一个string类型的变量 用于存放【文件路径】 string[] splitName = oldName.Split('.'); //为获取文件的扩展名做准备的 string ext = splitName[splitName.Length - 1]; //文件的扩展名 if (ext == "jpg" || ext == "gif" || ext == "bmp" || ext == "JPG") //限制上传图片的格式 { string dbName = DateTime.Now.ToString("yyyyMMddhhmmss") + "." + ext; //给上传的图片起个名字!以时间命名 string newName = AppDomain.CurrentDomain.BaseDirectory + dbName; //新路径!这是个相对路径 File.Copy(oldName, newName, true); //把文件从以前的路径复制到新的路径中去 //下面就开始添加到数据库里面了 string constring="";//数据库的连接字符串 using (SqlConnection con=new SqlConnection (constring)) { con.open(); stirng sql="insert into shujukuname (name) values(@name)"; //因为id自增的这里只需要添加图片名称 SqlCommand cmd = new SqlCommand(sql,con); cmd.Parameters.Add("@name",SqlDbType.VarChar).Value=TextBox1.Text.Trim(); cmd.ExecuteNonQuery(); con.Close(); } } }
方法二:直接把图片添加在sqlserver中
首先要有一个image或者binary类型的字段,这种是以二进制形式插入到数据库中, 清理资源
FileStream fs = new FileStream(pathName, System.IO.FileMode.Open, System.IO.FileAccess.Read); byte[] buffByte = new byte[fs.Length]; fs.Read(buffByte, 0, (int)fs.Length); fs.Close(); //数据库字段为image类型,将图片转化为byte[],保存到数据库 SqlConnection db = new SqlConnection(strConn); db.Open(); string strSQL = "INSERT INTO shujuktable (name) values (@name) "; SqlCommand cmd = new SqlCommand(strSQL, db); cmd.Parameters.Add( "@name", SqlDbType.Image); cmd.Parameters[ "@name"].Value = buffByte; cmd.ExecuteNonQuery(); //保存图片的过程