C# WinForm DataGridView控件粗解及MySql数据库操作

目录

一:阅读须知

二:什么是DataGridView控件

三:自定义DataGridView控件

3.1 DataGridView显示内容初始化

3.1.1 布局

3.1.2 设计

3.1.3 外观

3.1.4 行为

3.1.5 通过事件进行初始化

3.2 DataGridView显示设计及功能实现

3.2.1 鼠标事件

3.2.2 焦点事件

3.2.3 变更事件

四:数据

4.1 数据类型

4.1.1 DataTable

4.1.2 DataSet

4.1.3 DataGridViewCellEventArgs e

4.1.4 DataGridViewRowCollection

4.1.5 DataGridViewColumnCollection

4.1.6 DataGridViewCellCollection

4.2 属性

4.2.1 获取行号与列号

4.2.2 获取DataGridView控件的总行数

4.3 内置控件的属性与方法

4.3.1 DataGridViewCheckBoxColumn

4.3.2 DataGridViewComboBoxColumn

4.3.3 DataGridViewLinkColumn

4.3.4 DataGridViewTextBoxColumn

五:绑定数据源

5.1 数据源简介

5.2 自定义数据源

5.3 读取MySql数据库并将数据集作为数据源

5.4 数据清空

5.5 获取数据源类型

六: 项目实战

6.1 项目简介

6.2 项目实现

6.2.1 项目注意事项

6.2.2 实现思路

6.2.3 子窗口代码实现

6.2.4 主窗口代码实现


一:阅读须知

1 最近在研究C#的DataGridView控件,针对所了解的知识做出总结,本博客只做学习探讨用途。

2 本文也包括WinForm程序中的一些其他常用控件的介绍。

3 粗解就是我个人粗略的,浅显的理解,有不对的地方请通知我及时探讨和更正,希望能给阅读的各位带来帮助。

4 本文中的一些代码或者文字可能因为我个人原因键入错误,看客诸君注意分别。

二:什么是DataGridView控件

以下通过内容通过网页搜索获得

DataGridView控件是一个功能强大的数据表格控件,它以网格(表格)的形式显示数据

以下是DataGridView控件的一些主要特点:

  1. 多种列类型:DataGridView支持多种列类型,包括TextBox、CheckBox、Image、Button、ComboBox和Link等,这使得它能够适应不同类型的数据展示需求。
  2. 数据操作:用户可以直接在DataGridView控件中修改数据,这为数据的即时编辑提供了便利。
  3. 行选择:当用户选中DataGridView控件中的某一行时,可以进行相应的操作,如获取当前单元格的数据等。
  4. 灵活性:DataGridView控件可以显示少量数据的只读视图,也可以缩放以显示特大数据表,提供了灵活的数据显示解决方案。
  5. 自定义行和列:这种控件允许用户定义行和列,以及对应的单元格,满足特定的数据显示和编辑需求。
  6. 事件处理:DataGridView还提供了丰富的事件模型,如单元格点击、数据改变等事件,方便开发者进行事件驱动的程序设计。
  7. 绑定数据源:可以将DataGridView控件绑定到各种数据源,如列表、数组或数据库查询结果,实现数据的动态加载和展示。
  8. 样式和格式:用户可以根据需要自定义单元格和表格的样式和格式,包括字体、颜色、边框等,以改善用户体验。
  9. 辅助功能:DataGridView还支持辅助功能,如键盘导航和屏幕阅读器支持,确保所有用户都能访问和操作表格数据。

       综上所述,DataGridView控件是Windows窗体应用程序中一个非常有用的工具,它提供了丰富的功能和灵活的操作,使得开发者能够轻松地在应用程序中实现数据的展示和编辑。

三:自定义DataGridView控件

       简介中介绍到DataGridView控件有多种列类型,本部分将介绍多种列类型的相关操作。首先自定义我的控件形式,如下图所示:

          上图中DataGridView控件中我添加了三个按钮(DataGridViewButtonColumn),一个复选框(DataGridViewCheckBoxColumn),一个下拉框(DataGridViewComboBoxColumn),一个文本框(DataGridViewTextBoxColumn),一个超链接(DataGridViewLinkColumn),一个图片(DataGridViewImageColumn)。当我运行程序效果如下:

       实际上我在最开始运行程序的效果并不是这样,按钮上并没有文字,仅仅有一个初始化的空行,这个空行出现的原因是我在创建此DataGridView控件时默认保留了ALLowUsertoAddRows属性,此属性允许用户去更改控件行数,所以会预初始化一行,当你选中复选框或选择下拉框或在文本框中键入文字后会生成新的一行。

注意

       保留ALLowUsertoAddRows属性时自动生成的行无法手动代码删除此行或者插入新行,如调用删除行函数Remove或者RemoveAt或insert(index+1,1)时会报错,提示有未提交而删除或者插入新行异常

3.1 DataGridView显示内容初始化

我曾经想通过编辑列的时候对按钮上显示的内容进行初始化,但是没有找到相关的属性

3.1.1 布局

AutoSizeMode属性

  1. AllCells: 调整列宽以适合该列中的所有单元格的内容,包括标题单元格。
  2. AllCellsExceptHeader: 调整列宽以适合该列中的所有单元格的内容,不包括标题单元格。
  3. ColumnHeader: 调整列宽以适合列标题单元格的内容。
  4. DisplayedCells: 调整列宽以适合当前屏幕上显示的行的列中的所有单元格的内容,包括标题单元格。
  5. DisplayedCellsExceptHeader: 调整列宽以适合当前屏幕上显示的行的列中的所有单元格的内容,不包括标题单元格。
  6. Fill: 调整列宽使所有列的宽度正好填充控件的显示区域,只需要水平滚动保证列宽在DataGridViewColumn.MinimumWidth 属性值以上。相对列宽由相对 DataGridViewColumn.FillWeight 属性值决定。
  7. None: 列宽不会自动调整。
  8. NotSet: 列的大小调整行为从 DataGridView.AutoSizeColumnsMode 属性继承。

DividerWidth属性

     此属性为列与列之间的间距

FillWeight属性

       在DataGridView控件中,FillWeight属性是用于指定当列的AutoSizeMode属性设置为Fill时,该列相对于其他同样设置了Fill的列的填充权重

具体来说,当DataGridView的AutoSizeColumnsMode属性设置为Fill时,所有列会根据它们的FillWeight属性值来分配额外的空间。这个额外的空间是指在调整DataGridView的大小以适应其容器时,除了列内容所需的最小宽度之外的空间。简单来说就是分配列宽的比重。

Frozen属性

       当DataGridView控件中的某一列的Frozen属性被设置为True时,该列以及其左侧的所有列将会被固定。这意味着在用户横向滚动DataGridView时,这些固定的列不会随着滚动条的移动而左右滑动,而是会保持在视图中的固定位置。这个功能特别适用于那些包含关键信息或者经常需要参考的列,通过冻结这些列,可以确保即使在滚动数据时,用户也能够持续看到这些重要信息。

MinimumWidth属性

      设置列的最小宽度,防止用户通过拖动调整列宽小于这个值。

Width 和 Height属性

       这两个属性分别控制列的宽度和高度。可以手动设置具体的数值,也可以让系统自动调整

3.1.2 设计

Name属性

       每一列都有一个唯一的名称,这在编程时用于引用特定的列。也就是随机读取,例如在读取某行名为"age"一列的值时的实例代码为 string age =dataGridView1.Rows[e.RowIndex].Cells["age"] 

ColumnType属性

      就是列类型包括如下

按钮(DataGridViewButtonColumn),复选框(DataGridViewCheckBoxColumn)

下拉框(DataGridViewComboBoxColumn),文本框(DataGridViewTextBoxColumn)

超链接(DataGridViewLinkColumn),图片(DataGridViewImageColumn)

DataPropertyName

        在使用DataGridView时,通常会绑定一个数据源,这个数据源可能是一个对象列表、数据库查询结果集或者其他实现了IList接口的数据类型。为了正确显示和编辑数据,需要为DataGridView的每一列设置DataPropertyName属性。具体来说,DataPropertyName的作用如下:

  1. 绑定数据源属性:通过设置DataPropertyName属性,可以将DataGridView的某一列与数据源中的某个属性进行绑定。这样,列中显示的数据就会反映数据源对象中该属性的值。
  2. 支持复杂属性:如果数据源中的属性是复杂的或者是一个嵌套的对象,可以通过设置DataPropertyName来访问这些复杂属性的内部字段。例如,如果数据源有一个名为ClassTest的属性,而这个属性又包含了S1和S2两个子属性,那么可以设置DataPropertyName为"ClassTest.S1"或"ClassTest.S2"来分别绑定这两个子属性。
  3. 中文列名与英文属性名匹配:在实际应用中,通常希望DataGridView的列名以中文显示,而数据源的属性名则保持英文。通过设置DataPropertyName属性,可以实现这种中英文匹配的需求。在列的属性中设置HeadText为中文列名,而DataPropertyName则指向英文的属性名。
  4. 添加和编辑列:在设计时或运行时,都可以通过DataGridView的列集合来添加或编辑列。在列编辑器中,可以为每一列设置DataPropertyName属性,以便与数据源中的属性建立关联。

总的来说,DataPropertyName属性在DataGridView控件中扮演着桥梁的角色,它将控件的列与数据源的属性连接起来,确保了数据的准确显示和有效编辑。

3.1.3 外观

DefaultCellStyle属性

       允许开发者定义DataGridView中单元格的默认外观和行为。这包括字体、颜色、对齐方式等。通过设置这一属性,可以确保新添加的数据行中的单元格自动继承这些样式,除非为特定单元格单独设置了样式。

dataGridView1.Columns["ColumnName"].DefaultCellStyle.Font = new Font(dataGridView1.Font, FontStyle.Bold);
dataGridView1.Columns["ColumnName"].DefaultCellStyle.ForeColor = Color.Red;
dataGridView1.Columns["ColumnName"].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
dataGridView1.Columns["ColumnName"].DefaultCellStyle.Format = "C"; // 货币格式
dataGridView1.Columns["ColumnName"].DefaultCellStyle.NullValue = "N/A"; // 空值显示为"N/A"

FlatStyle属性

  • Flat:这是默认的样式,它会使得控件看起来是平面的,没有3D效果或阴影。
  • Popup:这种样式会给控件添加一个3D效果,使其看起来像是浮动在窗体上方。
  • Standard:这是传统的Windows风格的外观,通常带有3D边缘和阴影效果。

HeaderText属性

    此属性可以设置列标题

Text属性

   有回答说Text属性用于设置或获取单元格的文本内容。

注意

1 当新建一个DataGriView控件时,会默认打开ALLowUsertoAddRows属性,会在程序运行时初始化一个空行,此行上不会在程序运行时显示设置的Text文本,而当我们有添加新行操作时(选中复选框,在文本框中输入文本,点击按钮用代码添加新行等)会随着新行被添加而显示文本

2 使用此文本要将useColumnTextForButton属性设置为True

3 如果你通过代码或者自动添加新行请注意如果useColumnTextForButton被设置为True,你的代码设置的文本可能会被覆盖

TooltipText属性

    用于设置或获取单元格的提示文本,我设置以后测试结果时鼠标悬停在列标题上会有提示

UseColumnTextForButtonValue属性
   指示是否将DataGridViewButtonColumn.Text 属性值显示为此列中单元格的按钮文本。

visible属性

     此属性指示程序运行时此列是否可视

3.1.4 行为

ContextMenuStrip属性

     列的快捷菜单,用于设置或获取DataGridView的上下文菜单

ReadOnly和ReSizable属性

    分别是此列是否只读和此列是否可以改变宽高

SortMode属性

    排序方式

3.1.5 通过事件进行初始化

   在主界面Load事件中对DataGridView控件的每行每列进行初始化

//以下标的方式给按扭添加显示文本
dataGridView1.Rows[0].Cells[1].Value = "添加新行";
//以下标的方式给下拉框添加选项
((DataGridViewComboBoxCell)dataGridView1.Rows[0].Cells[3]).Items.Add("默认值");
//设置指定Name属性的单元格内容
//设置超链接初始化文本
dataGridView1.Rows[0].Cells["cHref"].Value = "http://www.baidu.com";
//设置复选框初始选中
dataGridView1.Rows[0].Cells["cCheck"].Value = true;

3.2 DataGridView显示设计及功能实现

本部分以我自己设计的控件样式及常用事件举例

3.2.1 鼠标事件

CellContentClick事件

当点击DataGridView中的不同类型的控件时触发,并在事件中以列标区分

private void dataGridView1_CellContentClick(object sender, DataGridViewCellEventArgs e)
{
    string text = "";

    /* ALLowusertoAddRows属性相当于默认添加一个空行,此行不可删除,添加时也要注意未提交异常 
     
     */
    //获取文本内容
    if (e.ColumnIndex == 0) //获取事件单元格的列索引,判断如果是点击了第一列的按钮
    {
        try
        {
            

                if (dataGridView1.Rows.Count != 1) //ALLowUsertoAddRows属性设置为True后默认会有一个空行,不能删除,否则有空引用异常,可以用行数判断
                {
                    if (dataGridView1.Rows[e.RowIndex].Cells[4].Value != null )
                        text = this.dataGridView1.Rows[e.RowIndex].Cells[4].Value.ToString();//获取文本框这一列(0,1,2,3)的当前行数据
                    else
                        text = "空";
                    this.dataGridView1.Rows.RemoveAt(e.RowIndex);
                    MessageBox.Show(text);
                }
                else //没有插入数据会出现删除默认行的形况情况错误

                {
                    MessageBox.Show("表格设置了ALLowUsertoAddRows属性,第一行无法删除");
                    return;
                }
                
           
            

          
           
                
        }

        //不绑定数据源,删除datagridview中的行 ALLowUsertoAddRows 这个属性设置是true时,默认会显示出来一行空行,这个空行不能删除,删除会报错


        catch
        {
            MessageBox.Show("空行无法删除");
        }
    }
    /*
     * 在当前行插入新行
     点击第二个按钮插入新行,因为有ALLowUsertoAddRows属性,直接插入会有未提交而插入新行异常,可以在已存在的某行与某行之间插入一行但是不能在默认行插入
     */
    if (e.ColumnIndex==1)
    {
         if(e.RowIndex+1!=dataGridView1.Rows.Count)
        {
            dataGridView1.Rows.Insert(e.RowIndex + 1, 1);
            dataGridView1.Rows[e.RowIndex+1].Cells[0].Value = "删除此行";
            dataGridView1.Rows[e.RowIndex+1].Cells[1].Value = "添加新行";
        }
        else
        {
            DataGridViewRow row= new DataGridViewRow();
            row.CreateCells(dataGridView1); //将创建一个与列表样式相同的行
            row.Cells[0].Value = "删除此行";
            row.Cells[1].Value= "添加新行";
            row.Cells[7].Value = "复选框状态取反";
            ((DataGridViewComboBoxCell)row.Cells[3]).Items.Add("默认值");
            dataGridView1.Rows.Add(row);
        }
            
        MessageBox.Show(dataGridView1.Columns[2].Name);//输出第三列的Name属性
        
    }
    //复选框
    if (e.ColumnIndex == 2)
    {
        string isCheck = dataGridView1.Rows[e.RowIndex].Cells[2].EditedFormattedValue.ToString();//获取复选框状态

        //bool isChecked=false;

         DataGridViewCheckBoxCell cell = dataGridView1.Rows[e.RowIndex].Cells[2] as DataGridViewCheckBoxCell;
        //if (dataGridView1.Rows[e.RowIndex].Cells["cCheck"].Value!=null)
        //      isChecked= (bool)dataGridView1.Rows[e.RowIndex].Cells["cCheck"].Value;
        //else
        //{
        //    MessageBox.Show("列表控件未初始化");
        //    return;
        //}
        //if (cell != null&&cell.Value!=null)
        //{
        //    isChecked = (bool)cell.Value;
        //}
        // if(isChecked==true)  

        if (isCheck == "True" || isCheck == "true") //注意是大写的True
        {
            //MessageBox.Show("已选中");
//给下拉框添加内容
            ((DataGridViewComboBoxCell)this.dataGridView1.Rows[e.RowIndex].Cells["Column3"]).Items.Add("11");
        }
        else
        //MessageBox.Show("未选中");
        {
            ((DataGridViewComboBoxCell)this.dataGridView1.Rows[e.RowIndex].Cells["Column3"]).Items.Add("22");
            ((DataGridViewComboBoxCell)this.dataGridView1.Rows[e.RowIndex].Cells["Column3"]).Items.Remove("11");
        }
    }
    
    if(e.ColumnIndex==4)
    {
        dataGridView1.Rows[e.RowIndex].Cells[0].Value= "删除此行";
        dataGridView1.Rows[e.RowIndex].Cells[1].Value = "添加新行";
    }
    //点击超链接
    if(e.ColumnIndex==5)
    {   //要启动的程序,传给启动程序的参数=》要打开的浏览器,打开的网址
        System.Diagnostics.Process.Start("iexplore.exe", this.dataGridView1.Rows[0].Cells["cHref"].Value.ToString());
    }
    //添加按钮控件 反转复选框选中状态
    if (e.ColumnIndex==7)
    {
        string item,isCheck = dataGridView1.Rows[e.RowIndex].Cells[2].EditedFormattedValue.ToString();//获取复选框状态
        if (isCheck == "True" || isCheck == "true") //注意是大写的True
        {
            dataGridView1.Rows[e.RowIndex].Cells[2].Value = false;//直接设置
        }
        else
            dataGridView1.Rows[e.RowIndex].Cells[2].Value = true;

        // 刷新 DataGridView 以显示更改
        dataGridView1.RefreshEdit();
        if (((DataGridViewComboBoxCell)this.dataGridView1.Rows[e.RowIndex].Cells["Column3"]).Value != null)
        {   item = ((DataGridViewComboBoxCell)this.dataGridView1.Rows[e.RowIndex].Cells["Column3"]).Value.ToString();
            MessageBox.Show(item);
         }
        else
        {
            MessageBox.Show("未选中下拉框的任何值");
        }
    }
}

3.2.2 焦点事件

//此事件指示当鼠标点击DataGridView控件时触发什么效果 
private void dataGridView1_RowEnter(object sender, DataGridViewCellEventArgs e)
 {
     dataGridView1.Rows[e.RowIndex].Cells[0].Value = "删除此行";
     dataGridView1.Rows[e.RowIndex].Cells[1].Value = "添加新行";
 }

3.2.3 变更事件

 private void dataGridView1_CellValueChanged(object sender, DataGridViewCellEventArgs e)
 {
     if (dataGridView1.Columns[e.ColumnIndex] is DataGridViewTextBoxColumn)
     {
         // 获取更改后的单元格
         if(e.RowIndex>=0)
         if (dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex] != null)
         {
             DataGridViewCell cell = dataGridView1.Rows[e.RowIndex].Cells[e.ColumnIndex];
             string newValue = cell.Value.ToString();

             // 验证输入是否为数字
             if (!int.TryParse(newValue, out int number))
             {
                 // 显示错误消息
                 MessageBox.Show("请输入有效的数字!");

                 // 恢复原始值
                 cell.Value = dataGridView1.CurrentCell.EditedFormattedValue;
             }
             else
                 {
                     MessageBox.Show(newValue);
                 }
         }
             
     }

注意

1 不知道是我个人配置的原因还是原来就是这样,这个我也没有进行验证。我程序启动的时候就会触发判断值有没有发生改变,并且会有出现System.ArgumentOutOfRangeException:“索引超出范围的问题,调试过程中发现我的索引值(e.RowIndex值为-1)为了处理这个问题我在上述代码中加入了值判断。

2 为了完善判错机制,在后续的值判断处理中有判空操作

四:数据

4.1 数据类型

4.1.1 DataTable

在C#中,DataTable是一种数据类型,用于表示内存中的数据表。它是.NET Framework中System.Data命名空间的一部分,通常用于存储和管理数据集(DataSet)中的数据。

以下是关于DataTable的一些基本信息:

  1. 列和行:DataTable由列(DataColumn)和行(DataRow)组成,可以动态地添加、删除或修改。
  2. 数据类型:DataTable可以存储多种类型的数据,包括字符串、数字、日期等。
  3. 约束:可以为DataTable中的列定义各种约束,如主键、外键、唯一性约束等。
  4. 关系:可以在DataTable之间建立关系,以便在多个表之间创建逻辑联系。
  5. 查询:可以使用类似于SQL的查询语言来查询DataTable中的数据。
  6. 事件:DataTable提供了一系列的事件,如RowChanged、RowDeleted等,可以用来响应数据表中数据的变化。
  7. 扩展性:DataTable是可扩展的,可以通过继承和实现接口来自定义数据表的行为。
  8. 序列化:DataTable可以被序列化,以便在网络上传输或保存到文件中。

总的来说,DataTable是C#中处理表格数据的强有力工具,它提供了丰富的功能和方法来操作和管理数据。

//DataTable示例代码
// 创建一个新的DataTable对象
        DataTable table = new DataTable("SampleTable");

        // 按多种数据类型添加列
        table.Columns.Add("Name", typeof(string));//产品名称
        table.Columns.Add("Price", typeof(decimal));//产品价格
        table.Columns.Add("Date", typeof(DateTime));//产品生产日期
        table.Columns.Add("Quantity", typeof(int));//产品等级
        table.Columns.Add("IsAvailable", typeof(bool));//产品是否有库存

        // 添加行
        /*
          在C#中,10.99m表示一个十进制数,其中10.99是数值部分,而m是一个后缀,用于指示该数值为decimal类型。

在C#中,decimal是一种高精度的浮点数类型,用于表示精确的小数值。它比float和double类型具有更高的精度和范围,适用于需要精确计算的场景,如货币、金融等。

因此,10.99m表示一个decimal类型的数值,其值为10.99。
        */
        table.Rows.Add("Item1", 10.99m, DateTime.Now, 5, true);
        table.Rows.Add("Item2", 19.99m, DateTime.Now, 3, false);
        table.Rows.Add("Item3", 7.99m, DateTime.Now, 8, true);
        table.Rows.Add("Item4", 14.99m, DateTime.Now, 2, true);
        table.Rows.Add("Item5", 24.99m, DateTime.Now, 6, false);

        // 打印DataTable中的数据
        foreach (DataRow row in table.Rows)
        {
            Console.WriteLine($"Name: {row["Name"]}, Price: {row["Price"]}, Date: {row["Date"]}, Quantity: {row["Quantity"]}, IsAvailable: {row["IsAvailable"]}");
        }
    }

4.1.2 DataSet

C#中的DataSet是一种数据集合类,用于表示一组相关的DataTable对象。它是.NET Framework中System.Data命名空间的一部分,通常用于管理数据库查询结果和缓存数据。

以下是关于DataSet的一些详细信息:

  1. 组成:DataSet由一个或多个DataTable对象组成,每个DataTable代表一个数据表。DataSet还可以包含DataRelation对象,用于表示表之间的关系。
  2. 功能:DataSet提供了丰富的功能,包括数据查询、排序、过滤等,支持对数据进行增删改查操作。
  3. 用途:DataSet常用于在内存中缓存数据,以便在不连接数据库的情况下对数据进行处理。它也可以用于在不同的数据源之间传输数据。
  4. 结构:DataSet具有层次化的结构,可以表示复杂的数据关系。它可以包含多个DataTable,每个DataTable又包含多个DataColumn和DataRow。
  5. 事件:DataSet提供了一系列的事件,如RowChanged、RowDeleted等,可以用来响应数据表中数据的变化。
  6. 扩展性:DataSet是可扩展的,可以通过继承和实现接口来自定义数据集合的行为。
  7. 序列化:DataSet可以被序列化,以便在网络上传输或保存到文件中。
  8. 与数据库交互:DataSet可以与数据库进行交互,通过DataAdapter对象来填充数据和提交更改。

总的来说,DataSet是C#中处理数据集的强大工具,它提供了丰富的功能和方法来操作和管理数据。


/*一段使用Dataset的示例代码,数据集中有两个表格,
一个是学生信息表,另一个是计算机部件价格表。
这两个表又分别作为两个datagridview的控件的数据源
*/

// 创建一个新的DataSet对象
DataSet dataSet = new DataSet("StudentAndParts");

// 创建学生信息表
DataTable studentTable = new DataTable("StudentInfo");
studentTable.Columns.Add("ID", typeof(int));
studentTable.Columns.Add("Name", typeof(string));
studentTable.Columns.Add("Age", typeof(int));
studentTable.Rows.Add(1, "张三", 20);
studentTable.Rows.Add(2, "李四", 22);
studentTable.Rows.Add(3, "王五", 21);
dataSet.Tables.Add(studentTable);

// 创建计算机部件价格表
DataTable partsTable = new DataTable("ComputerParts");
partsTable.Columns.Add("PartName", typeof(string));
partsTable.Columns.Add("Price", typeof(decimal));
partsTable.Rows.Add("CPU", 500.0m);
partsTable.Rows.Add("GPU", 800.0m);
partsTable.Rows.Add("RAM", 200.0m);
dataSet.Tables.Add(partsTable);

// 将DataSet绑定到两个DataGridView控件
dataGridView1.DataSource = dataSet.Tables["StudentInfo"];
dataGridView2.DataSource = dataSet.Tables["ComputerParts"];

4.1.3 DataGridViewCellEventArgs e

       将提供数据供DataGridView与单元格和行操作相关的事件。简单来说就是出发事件后能通过此类型的变量获取出发事件时所在的行(e.RowIndex()),列(e.ColumnInex()),值等。

4.1.4 DataGridViewRowCollection

     获取一个集合,该集合包含DataGirdView控件中的所有行,每一行是一个DataGridViewRow

foreach (DataGridViewRow row in dataGridView1.Rows)
{
    // 在这里处理每一行的数据
}
//其中的datagridview1为一个DataGridView控件对象,
//它的Rows属性是一个DataGridViewRowCollection对象

4.1.5 DataGridViewColumnCollection

    获取一个集合,包含DataGridView控件中的所有列 遍历方式如上

4.1.6 DataGridViewCellCollection

  填充行的单元格集合

foreach (DataGridViewRow row in dataGridView1.Rows)
{
    foreach (DataGridViewCell cell in row.Cells)
    {
        // 在这里处理每个单元格的数据
    }
}

4.2 属性

此部分指示代码中常用属性,全部属性见自定义DataGridView控件部分,所有属性对应的代码本文不在罗列

4.2.1 获取行号与列号

DataGridViewCellEventArgs e
e.RowIndex//行号
e.ColumnIndex//列号

4.2.2 获取DataGridView控件的总行数

dataGridView1.Rows.Count //此属性获取总行数
//根据获取到的行数,做出可以做出相应的操作

4.3 内置控件的属性与方法

DataGridView内置控件的点击触发已通过鼠标事件中有所介绍,本部分作补充。

本部分假设有一个DataGridView控件对象dataGridView1,也就是我最开呈现的设计图

4.3.1 DataGridViewCheckBoxColumn

//为某行某列类型为DataGridViewCheckBoxColumn的控件直接设置未选中状态
//方法一:索引设置
dataGridView1.Rows[e.RowIndex].Cells[2].Value = false;//直接设置
//方法二:通过名称与此列Name属性相同的单元格设置,例如此列Name属性为cCheck
dataGridView1.Rows[e.RowIndex].Cells["cCheck"].Value = false;//直接设置


//读取是否为选中状态

string isCheck = dataGridView1.Rows[e.RowIndex].Cells[2].EditedFormattedValue.ToString();//获取复选框状态
//已选中
if (isCheck == "True" || isCheck == "true") //注意是大写的True
{
    //MessageBox.Show("已选中");
}
//未选中
else
{
}

注意:

        EditedFormattedValue属性用来处理数据未提交异常。也就是不管数据有没有同步到数据源或者其他同步操作,都可以使用此属性获取当前值,如果采取获取Value属性再转换为bool或者string类型时,可能会提示有未提交的异常,这个异常我目前也不知道如何处理。

4.3.2 DataGridViewComboBoxColumn

//添加一个选项
((DataGridViewComboBoxCell)this.dataGridView1.Rows[e.RowIndex].Cells["Column3"]).Items.Add("新增选项");

//添加以列选项,此列中的选项还可以增加个数
((DataGridViewComboBoxCell)this.dataGridView1.Rows[e.RowIndex].Cells["Column3"]).Items.AddRange(new object[] { "111", "222", "333", "444" });

4.3.3 DataGridViewLinkColumn

//为超链接单元格填充超链接地址
 dataGridView1.Rows[e.RowIndex].Cells["cHref"].Value = "http://www.baidu.com";
//点击超链接时触发连接
System.Diagnostics.Process.Start("iexplore.exe", this.dataGridView1.Rows[0].Cells["cHref"].Value.ToString());

注意:  

1 点击超链接属于鼠标点击事件,这个可以在上述的鼠标事件中根据列下标或者列名进行触发,其他触发方式这里不再介绍。

2 Start方法中的第一个参数是要打开的文件,也就是浏览器,第二个参数也就是通过获取单元格超链接字符串。连起来就是将超链接字符串作为传入参数传递给打开的浏览器。至于第一个参数我测试过iexplore.exe,msedge.exe两个浏览器,效果一样,我不清楚是我电脑上没有IE浏览器而参数是IE浏览器导致直接选择了默认的Edge浏览器打开超链接还是其他的什么原因,此原因我并没有用谷歌或者qq浏览器验证。

4.3.4 DataGridViewTextBoxColumn

//为文本框控件设置值
 dataGridView1.Rows[e.RowIndex].Cells["cText"].Value = "设置值";

//获取文本框控件的值
if(dataGridView1.Rows[e.RowIndex].Cells["cText"]!=null)
string text=dataGridView1.Rows[e.RowIndex].Cells["cText"].Value.toString(); 

//设置文本框的值保留两位小数
dataGridView2.Columns[3].DefaultCellStyle.Format = "F";//默认保留全部小数 如果保留两位"N2"

五:绑定数据源

5.1 数据源简介

        数据源就是空间上显示数据的来源,包括通过DataTable自定义的数据源,从数据库中获取的数据源以及其他数据来源,本文介绍前两种。通过DataGridView.DataSource属性进行绑定。

5.2 自定义数据源

//***********************手动为datagridView2控件对象添加数据源********************
DataTable table = new DataTable();
table.Columns.Add("姓名", typeof(string));//字符串列
table.Columns.Add("性别", typeof(string));//
table.Columns.Add("年龄", typeof(int));//整型列
table.Columns.Add("成绩", typeof(decimal));//高精度浮点型列
           
table.Rows.Add("张三", "男", 20, 85.5m);
table.Rows.Add("李四", "女", 22, 90.0m);
table.Rows.Add("王五", "男", 24, 78.5m);
table.Rows.Add("赵六", "女", 21, 92.0m);

// 将DataTable对象设置为DataGridView的数据源 一旦绑定了数据源之后新增的行也会有原来行的属性
dataGridView2.DataSource = table;

// 将“政治面貌”列设置为DataGridViewComboBoxColumn类型单元
DataGridViewComboBoxColumn comboBoxColumn = new DataGridViewComboBoxColumn();
comboBoxColumn.HeaderText = "政治面貌";
comboBoxColumn.Name = "政治面貌";
comboBoxColumn.Items.AddRange(new object[] { "群众", "共青团员", "预备党员", "党员" });
//comboBoxColumn.DisplayMember = "群众";
dataGridView2.Columns.Insert(3, comboBoxColumn);

5.3 读取MySql数据库并将数据集作为数据源

这里C# WinForm与mysql数据库连接需要引入数据库模块,右键项目-》管理nuget包-》搜索mysql

using MySql.Data.MySqlClient;

string connectionStr = "server=数据库ip;user=root;database=你的数据库名;port=你的数据库端口号;password=你的数据库密码";
using (MySqlConnection connection = new MySqlConnection(connectionStr))
{   
   //方法一: Reader
    connection.Open();
    if (connection.State == ConnectionState.Open)
    {
        using (MySqlCommand command = new MySqlCommand("SELECT * FROM students", connection))
        {
            using (MySqlDataReader reader = command.ExecuteReader())
            {
                DataTable dataTable = new DataTable();
                dataTable.Load(reader);
                dataGridView2.DataSource = dataTable;
                dataGridView2.Columns[3].DefaultCellStyle.Format = "N2";//默认保留全部小数 如果保留两位"N2"
                dataGridView2.DataSource = dataTable;
            }
        }
    }

}
//方法二: Adapter
//using (MySqlConnection connection = new MySqlConnection(connectionStr))
//{
//    connection.Open();
//    using (MySqlCommand command = new MySqlCommand("SELECT * FROM students", connection))
//    {
//        using (MySqlDataAdapter adapter = new MySqlDataAdapter(command))
//        {
//            DataTable dataTable = new DataTable();
//            adapter.Fill(dataTable);
//            dataGridView2.DataSource = dataTable;
//        }
//    }
//}

注意:

1 server=你的数据库ip 这个数据库ip也就是目的地址或者服务器的ip 如果是本地的数据库可以填入localhost或者(local),二者的区别如下:

在连接数据库时,使用(local)通常意味着通过UNIX的socket进行本地连接,而localhost则表示通过标准的网络接口(如TCP/IP协议)进行连接。

  1. 连接方式:使用(local)作为服务器名时,通常指的是使用UNIX domain sockets来进行通信。这种方式不经过网络栈,直接在操作系统层面进行进程间通信。而localhost作为一个特殊的主机名,代表本机地址,它通常会通过回环网络接口(如127.0.0.1)进行通信。
  2. 性能差异:由于(local)使用的是socket文件进行通信,这种方式通常具有较低的延迟和较高的性能,因为它避免了网络协议栈的开销。相比之下,localhost需要经过网络协议栈,可能会受到网络配置和防火墙设置的影响。
  3. 兼容性:(local)通常只在UNIX系统中有效,而localhost则在所有操作系统中都被广泛支持。因此,localhost具有更好的跨平台兼容性。

综上所述,(local)和localhost在连接数据库时的主要区别在于连接方式、性能差异和兼容性。(local)通过UNIX socket连接,性能较高,但兼容性较差;而localhost通过网络接口连接,兼容性较好,但可能受到网络环境的影响。在实际应用中,应根据具体的数据库类型和操作系统环境选择合适的连接方式。

其次就是端口号,Mysql一般默认3306 其他的根据自己的设置的端口号也可以访问

2 注意判断数据库是否打开成功

3 using语句可以简单理解为一个资源回收机制,在using里创建的变量无论是否正常执行完语句都会被释放掉,对于一些需要及时释放的变量如数据库操作流 Reader,如果打开后不及时关闭释放会将数据库锁住导致无法进行其他操作。

5.4 数据清空

这里清空数据有两种情况,一种是仅仅清空DataGridView中显示数据而不是清空数据源,另一种是清空数据源

 DialogResult result = MessageBox.Show("仅清空数据而不是清空数据源?","清空提示", MessageBoxButtons.YesNo);
 if(result==DialogResult.Yes) //仅清空数据                                              
 {
     
     dt.Rows.Clear(); //这里可能会有一个错误,就是数据源未清空,数据就不能清空,实际情况根据自己要求清空
     
 }
 else if(result==DialogResult.No)//清空数据源
 {
     dataGridView2.DataSource = null;
     dataGridView2.Columns.Clear();
 }

5.5 获取数据源类型

object dataSource = dataGridView2.DataSource;
if (dataSource is DataTable)
    MessageBox.Show("DataGridView的数据源为DataTable");
else //根据自己的一些其他能够给DataGridView添加数据源的变量或者控件做判断,这里我就不判断了
    MessageBox.Show("DataGridView2的数据源未知");

六: 项目实战

6.1 项目简介

本部分能够实现的功能如下:

1 主窗口添加一个DataGridView控件,用于显示从Mysql数据库获取的数据

2 双击此控件的某行会弹出子窗口,此子窗口包括主窗口选中行的所有数据

3 在子窗口中修改数据后会更新到数据库,同时刷新主窗口显示

主窗口界面

子窗口界面

6.2 项目实现

6.2.1 项目注意事项

此项目在了解如何与MySql建立连接并获取数据后有三个需要注意的地方

1 子窗口如何获取来自主窗口指定行的数据

2 子窗口作出修改如何同步到数据库

3 子窗口作出的修改如何自动同步到主窗口显示

6.2.2 实现思路

1 重写子窗口的构造函数,包含需要显示的信息,当然也包括将用户选中的行号,方便更新显示

2 子窗口类创建委托事件以将修改内容返回给主窗口

3 当主窗口用户鼠标双击某行时触发事件来创建子窗口,同时传递参数,订阅子窗口的事件

4 当用户操作子窗口并保存数据后退出能够及时更新到主窗口

6.2.3 子窗口代码实现

using MySql.Data.MySqlClient;
using Org.BouncyCastle.Utilities.Encoders;
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;
using static System.Windows.Forms.VisualStyles.VisualStyleElement;
using System.Xml.Linq;

namespace winformTest
{
    public partial class Form2 : Form
    {
        public Form2(string id,string name, string sex, int age, float score,int rowIndex)
        {
            InitializeComponent();
            textBox1.Text = name;
            textBox2.Text = sex;
            textBox3.Text = age.ToString();
            textBox4.Text = score.ToString();
            textBox5.Text = id;

            //初始化data
            data=new Data();
            data.rowIndex = rowIndex;
            data.id = id;
            data.name = name;
            data.sex = sex;
            data.age = age;
            data.score = score;
            

        }
        private Data  data;
        //定义一个委托用于处理数据返回事件
        public delegate void returnData(object sender, Data data);
        //定义一个事件,用于触发数据返回事件
        public event returnData returnDataEvent;

        //子窗口上的确定按钮
        private void button2_Click(object sender, EventArgs e)
        {   
            //如果返回事件被订阅
            if(returnDataEvent!=null)
            {
                returnDataEvent(this, data);
            }
                
            this.Close();
        }
        //子窗口上的保存按钮
        private void button1_Click(object sender, EventArgs e)
        {
            string upDataSQL = string.Format("update students set name='{0}',sex='{1}',age={2},score={3} where id='{4}'",
                textBox1.Text,
                textBox2.Text,
                Convert.ToInt32(textBox3.Text),
                float.Parse(textBox4.Text),
                textBox5.Text
               );

            string connectionStr = "server=数据库服务ip;user=root;database=testwinform;port=你的端口号;password=你的密码";
            using (MySqlConnection connection = new MySqlConnection(connectionStr))
            {
                connection.Open();
                if (connection.State == ConnectionState.Open)
                {
                    using (MySqlCommand command = new MySqlCommand(upDataSQL, connection))
                    {
                        command.ExecuteNonQuery();
                    }

                }
            }
            
            data.id = textBox5.Text;
            data.name = textBox1.Text;
            data.sex = textBox2.Text;
            data.age = Convert.ToInt32( textBox3.Text);
            data.score = float.Parse( textBox4.Text);
            MessageBox.Show("数据保存成功");
        }
    }
    //定义数据集,用于将子窗口的数据返回到主窗口
    public partial class Data
    {
        public int rowIndex { get; set; }
        public string id { get; set; }
        public string name { get; set; }
        public string sex { get; set; }
        public int age { get; set; }
        public float score { get; set; }
    }
}

6.2.4 主窗口代码实现

private void dataGridView2_CellDoubleClick(object sender, DataGridViewCellEventArgs e)
{  
    string id = dataGridView2.Rows[e.RowIndex].Cells[0].Value.ToString();
    string name = dataGridView2.Rows[e.RowIndex].Cells[1].Value.ToString();
    string sex = dataGridView2.Rows[e.RowIndex].Cells[2].Value.ToString();
    int age= Convert.ToInt32( dataGridView2.Rows[e.RowIndex].Cells[3].Value.ToString());
    float score;
    string scoreStr;
    if (dataGridView2.Rows[e.RowIndex].Cells[4].Value != null)
        scoreStr = dataGridView2.Rows[e.RowIndex].Cells[4].Value.ToString();
    else
        return;
    bool result = float.TryParse(scoreStr,out score);
    if (result)
    {
        Form2 form = new Form2(id,name, sex, age, score,e.RowIndex);
        form.returnDataEvent += updateDataGirdView;//订阅子窗口的事件并指示收到订阅消息后的处理操作

        form.ShowDialog();
    }
    //else
        //MessageBox.Show("数据转化失败");
        return;
    
}

//子窗口定义一种委托并声明一种事件,主窗口订阅这个事件,当在子窗口进行操作时满足某种条件触发了此事件会将指定的数据返回到主窗口,主窗口根据订阅用途做出相应的处理
private void updateDataGirdView(object sender, Data data)
{
    dataGridView2.Rows[data.rowIndex].Cells[1].Value = data.name;
    dataGridView2.Rows[data.rowIndex].Cells[2].Value = data.sex;
    dataGridView2.Rows[data.rowIndex].Cells[3].Value = data.age.ToString();
    dataGridView2.Rows[data.rowIndex].Cells[4].Value = data.score.ToString();
    
}

  • 27
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C# 可视化 WinForm 中,可以使用 DataGridView 控件来显示数据,并且可以实现分页功能。下面是一个简单的实现分页功能的示例代码: 首先,在窗体中添加一个 DataGridView 控件和两个 Button 控件,一个用于上一页,一个用于下一页。然后在窗体的 Load 事件中,初始化 DataGridView 控件并设置数据源: ``` private void Form1_Load(object sender, EventArgs e) { // 初始化 DataGridView 控件 dataGridView1.AutoGenerateColumns = true; dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect; dataGridView1.MultiSelect = false; dataGridView1.ReadOnly = true; // 设置数据源 dataGridView1.DataSource = GetData(1, pageSize); } ``` 其中,GetData() 方法用于获取数据源,第一个参数表示当前页码,第二个参数表示每页显示的数据条数。这个方法需要根据具体的业务逻辑来实现。 接下来,实现上一页和下一页的按钮点击事件: ``` private void btnPrev_Click(object sender, EventArgs e) { if (currentPage > 1) { currentPage--; dataGridView1.DataSource = GetData(currentPage, pageSize); } } private void btnNext_Click(object sender, EventArgs e) { if (currentPage < totalPages) { currentPage++; dataGridView1.DataSource = GetData(currentPage, pageSize); } } ``` 其中,currentPage 表示当前页码,totalPages 表示总页数。在点击上一页和下一页按钮时,需要判断当前是否到达了第一页或最后一页,如果没有,则更新当前页码并重新设置数据源。 最后,需要根据总数据条数和每页显示的数据条数计算总页数,并在窗体中显示出来: ``` private void DisplayPageInfo() { // 计算总页数 int totalCount = GetTotalCount(); totalPages = (int)Math.Ceiling((double)totalCount / pageSize); // 显示当前页码和总页数 lblPageInfo.Text = string.Format("第 {0} 页,共 {1} 页", currentPage, totalPages); } ``` 其中,GetTotalCount() 方法用于获取总数据条数,需要根据具体的业务逻辑来实现。 完整的代码示例: ``` public partial class Form1 : Form { private int pageSize = 10; // 每页显示的数据条数 private int currentPage = 1; // 当前页码 private int totalPages = 0; // 总页数 public Form1() { InitializeComponent(); } private void Form1_Load(object sender, EventArgs e) { // 初始化 DataGridView 控件 dataGridView1.AutoGenerateColumns = true; dataGridView1.SelectionMode = DataGridViewSelectionMode.FullRowSelect; dataGridView1.MultiSelect = false; dataGridView1.ReadOnly = true; // 设置数据源 dataGridView1.DataSource = GetData(1, pageSize); // 显示当前页码和总页数 DisplayPageInfo(); } private void btnPrev_Click(object sender, EventArgs e) { if (currentPage > 1) { currentPage--; dataGridView1.DataSource = GetData(currentPage, pageSize); DisplayPageInfo(); } } private void btnNext_Click(object sender, EventArgs e) { if (currentPage < totalPages) { currentPage++; dataGridView1.DataSource = GetData(currentPage, pageSize); DisplayPageInfo(); } } private void DisplayPageInfo() { // 计算总页数 int totalCount = GetTotalCount(); totalPages = (int)Math.Ceiling((double)totalCount / pageSize); // 显示当前页码和总页数 lblPageInfo.Text = string.Format("第 {0} 页,共 {1} 页", currentPage, totalPages); } private DataTable GetData(int pageNum, int pageSize) { // 根据当前页码和每页显示的数据条数获取数据源 // 这里只是一个示例,需要根据具体的业务逻辑来实现 DataTable dt = new DataTable(); dt.Columns.Add("ID", typeof(int)); dt.Columns.Add("Name", typeof(string)); dt.Columns.Add("Age", typeof(int)); for (int i = 1; i <= pageSize; i++) { int id = (pageNum - 1) * pageSize + i; dt.Rows.Add(id, "Name" + id, 20 + i); } return dt; } private int GetTotalCount() { // 获取总数据条数 // 这里只是一个示例,需要根据具体的业务逻辑来实现 return 100; } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值