C#学习之旅(四)

C#学习之旅(四)

文章目录

  • C#学习之旅(四)
    •         1、DataGridView数据控件
      •         1.1、DataGridView控件概述
      •         1.2、在DataGridView控件中显示数据
      •         1.3、获取DataGridView控件中的当前单元格
      •         1.4、直接在DataGridView控件中修改数据
      •         1.5、当选中DataGridView控件中的行时显示不同的颜色
      •         1.6、禁止在DataGridView控件中添加和删除行
      •         1.7、使用Columns和Rows属性添加数据
    •         2、LINQ数据访问技术
      •         2.1、LINQ基础
        •         2.1.1、LINQ概述
        •         2.1.2、使用var创建隐形局部变量
        •         2.1.3、Lambda表达式的使用
        •         2.1.4、LINQ查询表达式
      •         2.2、LINQ操作SQL Server数据库
        •         2.2.1、使用LINQ查询SQL Server 数据库
        •         2.2.2、使用LINQ管理SQL Server 数据库
      •         2.3、LINQ操作其他数据
        •         2.3.1、使用LINQ操作数组和集合
        •         2.3.2、使用LINQ操作DataSet数据集
        •         2.3.3、使用LINQ操作XML
    •         3、程序调试与异常处理
      •         3.1、程序调试概述
      •         3.2、常用的程序调试操作
      •         3.3、异常处理概述
      •         3.4、异常处理语句

        1、DataGridView数据控件

        开发WinForms应用程序需要使用数据库存储数据。使用DataGridView控件可以快速的将数据库中的数据显示给用户,并且可以通过DataGridView控件直接对数据进行操作。大大增强了操作数据库的效率。

        1.1、DataGridView控件概述

        DataGridView控件提供一种强大而灵活的以表格形式显示数据的方式。可以使用DataGridView控件来显示少量数据的只读视图,也可以对其进行缩放以显示特大数据集的可编辑视图。使用DataGridView控件,可以显示和编辑来自多种不同类型的数据源的表格数据。将数据绑定到DataGridView控件非常简单和直观,在大多数情况下,只需设置DataSource属性即可。DataGridView控件具有极高的可配置性和可扩展性,它提供了大量的属性、方法和事件,可以用来对该控件的外观和行为进行自定义。当需要在Windows窗体应用程序中显示表格数据时,首先考虑使用DataGridView控件。若要以小型网格显示只读值或者使用户能够编辑具有数百万条记录的表,DataGridView控件将提供可以方便地进行编程以及有效地利用内存的解决方案。

        1.2、在DataGridView控件中显示数据

        (1)、通过DataGridView控件显示数据表中的数据,首先需要使用DataAdapter对象查询指定的数据,然后通过该对象的Fill方法填充DataSet(关于DataAdapter对象以及Fill方法可参见C#学习之旅(三)内容),最后设置DataGridView控件的DataSource属性为DataSet的表格数据。DataSource属性用于获取或设置DataGridView控件所显示数据的数据源。
    语法:
        public Object DataSource { get; set; }
        属性值:包含DataGridView控件要显示的数据的对象。

C#学习之旅(四)_第1张图片

        1.3、获取DataGridView控件中的当前单元格

        (1)、若要与DataGridView进行交互,通常要求通过编程方式发现哪个单元格处于活动状态。如果需要更改当前单元格,可通过DataGridView控件的CurrentCell属性来获取当前单元格信息。
    CurrentCell属性用于获取当前处于活动状态的单元格。
    语法:
        public DataGridViewCell CurrentCell { get; set; }
        属性值:表示当前单元格的DataGridViewCell,如果没有当前单元格,则为空引用。默认值是第一列中的第一个单元格,如果控件中没有单元格,则为空引用。

C#学习之旅(四)_第2张图片
        (2)、可以通过DataGridView控件的SelectedCells属性集获取该控件中被选中的单元格信息。

        1.4、直接在DataGridView控件中修改数据

        (1)、在DataGridView控件中修改数据,主要用到DataTable的ImportRow方法和DataAdapter对象的Update方法。实现的过程是通过DataTable的ImportRow方法将更改后的数据复制到一个DataTable中,然后通过DataAdapter对象的Update方法,将DataTable中的数据更新到数据库中。
    ImportRow方法用于将DataRow复制替换到DataTable中,保留任何属性设置以及初始值和当前值。
    语法:
        public void ImportRow (DataRow row)
        row:要导入的DataRow。
    DataAdapter对象的Update方法在C#学习之旅(三)已经做过详细介绍,此处不再赘。

C#学习之旅(四)_第3张图片
C#学习之旅(四)_第4张图片
        (2)、默认情况下,用户可以通过在当前DataGridView文本框单元格中输入或按F2键来编辑该单元格内容。在控件单元格中编辑内容的前提是DataGridView控件已启用以及单元格、行、列和控件的ReadOnly属性都设置为false。ReadOnly属性用于指示用户是否可以编辑DataGridView控件的单元格。

        1.5、当选中DataGridView控件中的行时显示不同的颜色

        (1)、 可以利用DataGridView控件的SelectionMode、ReadOnly和SelectionBackColor属性实现当选中DataGridView控件中的行时显示不同的颜色。
    ①、SelectionMode用于设置如何选择DataGridView的单元格。
        语法:
            public DataGridViewSelectionMode SelectionMode { get; set; }
            属性值:DataGridViewSelectionMode值之一,默认RowHeaderSelect

        (DataGridViewSelectionMode枚举值及说明)
        
    ②、ReadOnly属性用于设置是否可以编辑DataGridView控件的单元格。
        语法:
        public bool ReadOnly { get; set; }
        属性值:如果用户不能编辑DataGridView控件的单元格,则为true;否则为false。默认为false。
    ③、SelectionBackColor属性用于设置DataGridView单元格在被选定时的背景色。
        语法:
        public Color SelectionBackColor { get; set; }
        属性值:Color,它表示选定单元格的背景色,默认为Empty。

C#学习之旅(四)_第5张图片

        1.6、禁止在DataGridView控件中添加和删除行

        (1)、通过设置DataGridView控件的公共属性AllowUserToAddRows、AllowUserToDeleteRows和ReadOnly,可以禁止在DataGridView控件中添加和删除行。AllowUserToAddRows属性设置一个值,该值指示是否向用户显示添加行的选项;AllowUserToDeleteRows属性设置一个值,该值指示是否允许用户从DataGridView中删除行;ReadOnly属性设置一个指示网格是否处于只读模式的值。

dataGridView1.AllowUserToAddRows = false;	     //禁止添加行
dataGridView1.AllowUserToDeleteRows = false;     //禁止删除行
dataGridView1.ReadOnly = true;	                 //控件中的数据为只读

        1.7、使用Columns和Rows属性添加数据

        (1)、通过设置DataGridView控件的Columns和Rows属性值,可以向数据控件DataGridView添加数据项,使其能够手动添加数据。
    ①、Columns属性用于获取一个包含控件中所有列的集合。
        语法:
            public DataGridViewColumnCollection Columns { get; }
            属性值:一个DataGridViewColumnCollection,包含DataGridView控件中的所有列。
    ②、Rows属性获取一个集合,该集合包含DataGridView控件中的所有行
        语法:
            public DataGridViewRowCollection Rows { get; }
            属性值:一个DataGridViewRowCollection,包含DataGridView控件中的所有行。

C#学习之旅(四)_第6张图片

        2、LINQ数据访问技术

         LINQ(Language-Integrated Query,语言集成查询)是微软公司提供的一项新技术,它能够将查询直接引入到.Net Framework 所支持的编程语言(如C#和VB.NET等)中。LINQ查询操作可以通过编程语言自身传达,而不是以字符串形式嵌入到应用程序代码中。

        2.1、LINQ基础

        2.1.1、LINQ概述

        (1)、LINQ是.Net Framework中一项突破性的创新,它在对象领域和数据领域之间架起了一座桥梁。LINQ主要由3部分组成,分别为LINQ to Objects、LINQ to ADO.NET和LINQ to XML。其中,LINQ to ADO.NET可以分为两部分,分别为LINQ to SQL 和LINQ to DataSet。LINQ的组成说明如下。
    ①、LINQ to SQL组件:可以查询基于关系数据库的数据,并对这些数据进行检索、插入、修改、删除、排序、聚合和分区等操作。
    ②、LINQ to DataSet组件:可以查询DataSet对象中的数据,并对这些数据进行检索、过滤和排序等操作。
    ③、LINQ to Objects组件:可以查询Ienumerable或Ienumerable集合,也就是说可以查询任何可枚举的集合,如数据(Array和ArrayList)、泛型列表List、泛型字典Dictionary以及用户自定义的集合,而不需要使用LINQ提供程序或API。
    ④、LINQ to XML组件:可以查询或操作XML结构的数据(如XML文档、XML片段和XML格式的字符串等),并提供了修改文档对象模型的内存文档和支持LINQ查询表达式等功能,处理XML文档的全新编程接口。
    LINQ可以查询或操作任何存储形式的数,如对象(集合、数组、字符串等)、关系(关系数据库、ADO.NET数据集等)以及XML。LINQ架构如图所示。

C#学习之旅(四)_第7张图片

        2.1.2、使用var创建隐形局部变量

        (1)、C# 1.0、1.1及2.0版本中,如果要声明一个变量,必须指定变量的类型,但在C#后期版本中声明变量时,可以不明确指定其数据类型,而使用关键字var来声明。var关键字用来创建隐型局部变量,它指示编译器根据初始化语句右侧的表达式推断变量的类型。推断类型可以是内置类型、匿名类型、用户定义类型、.NET Framework 类库中定义的类型或任何表达式。
    例如,使用var关键字声明一个隐型局部变量,并赋值为2022。代码如下:

var number = 2022; //声明隐型局部变量

        (2)、在很多情况下,var是可选的,它只是提供了语法上的便利。但在使用匿名类型初始化变量时,需要使用它,这在LINQ查询表达式中很常见。由于只有编译器知道匿名类型的名称,因此必须在源代码中使用var。如果已经使用var初始化了查询变量,则还必须使用var作为对查询变量进行循环访问的foreach语句中迭代变量的类型。

C#学习之旅(四)_第8张图片
        (3)、使用隐式类型的变量时,需要遵循以下规则。
    ①、只有在同一语句中声明和初始化局部变量时,才能使用var;不能将该变量初始化为null。
    ②、不能将var用于类范围的域。
    ③、由var声明的变量不能用在初始化表达式中,比如var v = v++; ,这样会产生编译时错误。
    ④、不能在同一语句中初始化多个隐式类型的变量。
    ⑤、如果一个名为var的类型位于范围中,则当尝试用var关键字初始化局部变量时,将产生编译时错误。

        2.1.3、Lambda表达式的使用

        (1)、Lambda表达式是一个匿名函数,它可以包含表达式和语句,并且可用于创建委托或表达式目录树类型。所有Lambda表达式都使用Lambda运算符“=>”,(读为goes to)。Lambda运算符的左边是输入参数(如果有),右边包含表达式或语句块。例如,Lambda表达式x => x * x读作x goes to x times x。Lambda表达式的基本形式如下:
    (input parameters) => expression
    其中,input parameters表示输入参数,expression表示表达式。

    技巧:
    ①、Lambda表达式用在基于方法的LINQ查询中,作为诸如Where和Where(IQueryable, String, Object[])等标准查询运算符方法的参数。
    ②、使用基于方法的语法在Enumerable类中调用Where方法时(像在LINQ to Objects和LINQ to XML中那样),参数是委托类型Func,使用Lambda表达式创建委托最为方便。

    注意:在is或as 运算符的左侧不允许使用Lambda表达式。

C#学习之旅(四)_第9张图片
        (2)、 下列规则适用于Lambda表达式中的变量范围:
    ①、捕获的变量将不会被作为垃圾回收,直至引用变量的委托超出范围为止。
    ②、在外部方法中看不到Lambda表达式内引入的变量。
    ③、Lambda表达式无法从封闭方法中直接捕获ref或out参数。
    ④、Lambda表达式中的返回语句不会导致封闭方法返回。
    ⑤、Lambda表达式不能包含其目标位于所包含匿名函数主体外部或内部的goto语句、break语句或continue语句。

        2.1.4、LINQ查询表达式

        (1)、语言集成查询(LINQ)是一组技术的名称,这些技术建立在将查询功能直接集成到C#语言(以及Visual Basic和可能的任何其他.NET语言)的基础上。借助于LINQ,查询现在已是高级语言构造,就如同类、方法和事件等。
    对于编写查询的开发人员来说,LINQ最明显的“语言集成”部分是查询表达式。查询表达式是使用C#中引入的声明性查询语法编写的。通过使用查询语法,开发人员可以使用最少的代码对数据源执行复杂的筛选、排序和分组操作,使用相同的基本查询表达式模式来查询和转换SQL数据库、ADO.NET数据集、XML文档和流以及.NET集合中的数据等。
    使用LINQ查询表达式时,需要注意以下几点。
    ①、查询表达式可用于查询和转换来自任意支持LINQ的数据源中的数据。例如,单个查询可以从SQL数据库检索数据,并生成XML流作为输出。
    ②、查询表达式容易掌握,因为它们使用许多常见的C#语言构造。
    ③、查询表达式中的变量都是强类型的,但许多情况下不需要显式提供类型,因为编译器可以推断类型。
    ④、在循环访问foreach语句中的查询变量之前,不会执行查询。
    ⑤、在编译时,根据C#规范中设置的规则将查询表达式转换为“标准查询运算符”方法调用。任何可以使用查询语法表示的查询都可以使用方法语法表示,但是多数情况下查询语法更易读和简洁。
    ⑥、作为编写LINQ查询的一项规则,建议尽量使用查询语法,只在必须的情况下才使用方法语法。
    ⑦、一些查询操作,如Count或Max等,由于没有等效的查询表达式子句,因此必须表示为方法调用。
    ⑧、查询表达式可以编译为表达式目录树或委托,具体取决于查询所应用到的类型。其中,IEnumerable查询编译为委托,IQueryable和IQueryable查询编译为表达式目录树。

        (2)、LINQ查询表达式包含8个基本子句,分别为from、select、group、where、orderby、join、let和into,其说明如表所示。

C#学习之旅(四)_第10张图片
C#学习之旅(四)_第11张图片

        2.2、LINQ操作SQL Server数据库

        2.2.1、使用LINQ查询SQL Server 数据库

        (1)、使用LINQ查询SQL数据库时,首先需要创建LinqToSql类文件。创建LinqToSql类文件的步骤如下。
    ①、启动Visual Studio 2017运行环境,建立一个窗体应用程序。
    ②、在“解决方案资源管理器”窗口中选中当前项目并右击,在弹出的快捷键菜单中选择“添加”—>“新建项"命令,弹出“添加新项”对话框。

C#学习之旅(四)_第12张图片
        ③、在“添加新项”对话框中选择“LINQ to SQL类”,在“名称”文本框中输入名称,单击“添加”按钮,添加一个LinqToSql类文件。
        ④、在“服务器资源管理器”窗口中连接SQL Server 2017数据库,然后将指定数据库中的表映射到.dbml中(可以将表拖拽到设计视图中)。

C#学习之旅(四)_第13张图片
        ⑤、.dbml文件将自动创建一个名称为DContext的数据上下文类,为数据库提供查询或操作数据库的方法,LINQ数据源创建完毕。DataContext类中的程序代码均自动生成。

C#学习之旅(四)_第14张图片
        ⑥、在Form1窗体插入以下代码,显示数据库中的数据。

namespace Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //定义数据库连接字符串
        string strCon = "Data Source=服务器名称;Database=数据库名称;Uid=sa;Pwd=密码;";
        //声明Linq连接对象
        linqtosqlClassDataContext linq;

        private void Form1_Load(object sender, EventArgs e)
        {
            BindInfo();
        }

        private void btnQuery_Click(object sender, EventArgs e)
        {
            BindInfo();
        }

        #region 查询员工信息
        /// 
        /// 查询员工信息
        /// 
        private void BindInfo()
        {
            //实例化Linq连接对象
            linq = new linqtosqlClassDataContext(strCon);

            if (txtKeyWord.Text == "")
            {
                //获取所有员工信息
                var result = from info in linq.tb_Employee
                             select new
                             {
                                 员工编号 = info.ID,
                                 员工姓名 = info.Name,
                                 性别 = info.Sex,
                                 年龄 = info.Age,
                                 电话 = info.Tel,
                                 地址 = info.Address,
                                 QQ = info.QQ,
                                 Email = info.Email
                             };
                dgvInfo.DataSource = result;            //对DataGridView控件进行数据绑定
            }
            else
            {
                switch (cboxCondition.Text)
                {
                    case "员工编号":
                        //根据员工编号查询员工信息
                        var resultid = from info in linq.tb_Employee
                                       where info.ID == txtKeyWord.Text
                                       select new
                                       {
                                           员工编号 = info.ID,
                                           员工姓名 = info.Name,
                                           性别 = info.Sex,
                                           年龄 = info.Age,
                                           电话 = info.Tel,
                                           地址 = info.Address,
                                           QQ = info.QQ,
                                           Email = info.Email
                                       };
                        dgvInfo.DataSource = resultid;
                        break;
                    case "员工姓名":
                        //根据员工姓名查询员工信息
                        var resultname = from info in linq.tb_Employee
                                         where info.Name.Contains(txtKeyWord.Text)
                                         select new
                                         {
                                             员工编号 = info.ID,
                                             员工姓名 = info.Name,
                                             性别 = info.Sex,
                                             年龄 = info.Age,
                                             电话 = info.Tel,
                                             地址 = info.Address,
                                             QQ = info.QQ,
                                             Email = info.Email
                                         };
                        dgvInfo.DataSource = resultname;
                        break;
                    case "性别":
                        //根据员工性别查询员工信息
                        var resultsex = from info in linq.tb_Employee
                                        where info.Sex == txtKeyWord.Text
                                        select new
                                        {
                                            员工编号 = info.ID,
                                            员工姓名 = info.Name,
                                            性别 = info.Sex,
                                            年龄 = info.Age,
                                            电话 = info.Tel,
                                            地址 = info.Address,
                                            QQ = info.QQ,
                                            Email = info.Email
                                        };
                        dgvInfo.DataSource = resultsex;
                        break;
                }
            }
        }
        #endregion
    }
}

C#学习之旅(四)_第15张图片
C#学习之旅(四)_第16张图片

        2.2.2、使用LINQ管理SQL Server 数据库

        使用LINQ管理SQL Server数据库时,主要有添加、修改和删除3种操作。

        (1)、添加数据:使用LINQ向SQL Server数据库中添加数据时,需要用到InsertOnSubmit方法和SubmitChanges方法。其中,InsertOnSubmit方法用来将处于pending insert状态的实体添加到SQL数据表中。其语法格式如下:
    void InsertOnSubmit(Object entity)
    其中,entity表示要添加的实体。
    SubmitChanges方法用来记录要插入、更新或删除的对象,并执行相应命令以实现对数据库的更改。其语法格式如下:
    public void SubmitChanges()

    插入以下代码,实现数据添加功能:

namespace Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        #region 定义公共变量及Linq连接对象
        //定义数据库连接字符串
        string strCon = "Data Source=服务器名称;Database=数据库名称;Uid=sa;Pwd=密码;";
        //声明Linq连接对象
        linqtosqlClassDataContext linq;          
        #endregion

        private void Form1_Load(object sender, EventArgs e)
        {
            BindInfo();
        }

        private void btnAdd_Click(object sender, EventArgs e)
        {
            //实例化Linq连接对象
            linq = new linqtosqlClassDataContext(strCon);
            //实例化tb_Employee类对象
            tb_Employee employee = new tb_Employee();   
            //为tb_Employee类中的员工实体赋值
            employee.ID = txtID.Text;
            employee.Name = txtName.Text;
            employee.Sex = cboxSex.Text;
            employee.Age = Convert.ToInt32(txtAge.Text);
            employee.Tel = txtTel.Text;
            employee.Address = txtAddress.Text;
            employee.QQ = txtQQ.Text;
            employee.Email = txtEmail.Text;

            //添加员工信息
            linq.tb_Employee.InsertOnSubmit(employee);
            //提交操作
            linq.SubmitChanges();                       
            MessageBox.Show("数据添加成功");
            BindInfo();
        }

        #region 显示所有员工信息
        /// 
        /// 显示所有员工信息
        /// 
        private void BindInfo()
        {
            //实例化Linq连接对象
            linq = new linqtosqlClassDataContext(strCon);   
            //获取所有员工信息
            var result = from info in linq.tb_Employee
                         select new
                         {
                             员工编号 = info.ID,
                             员工姓名 = info.Name,
                             性别 = info.Sex,
                             年龄 = info.Age,
                             电话 = info.Tel,
                             地址 = info.Address,
                             QQ = info.QQ,
                             Email = info.Email
                         };
            dgvInfo.DataSource = result;            //对DataGridView控件进行数据绑定
        }
        #endregion
    }
}

C#学习之旅(四)_第17张图片
        (2)、修改数据:使用LINQ修改SQL Server数据库中的数据时,需要用SubmitChanges()方法。
    插入以下代码,实现数据修改功能:

namespace Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        #region 定义公共变量及Linq连接对象
        //定义数据库连接字符串
        string strCon = "Data Source=服务器名称;Database=数据库名称;Uid=sa;Pwd=密码;";
        //声明Linq连接对象
        linqtosqlClassDataContext linq;							
        #endregion

        private void Form1_Load(object sender, EventArgs e)
        {
            BindInfo();
        }

        private void dgvInfo_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            //实例化Linq连接对象
            linq = new linqtosqlClassDataContext(strCon);    
            //获取选中的员工编号
            txtID.Text = Convert.ToString(dgvInfo[0, e.RowIndex].Value).Trim();
            //根据选中的员工编号获取其详细信息,并重新成成一个表
            var result = from info in linq.tb_Employee
                         where info.ID == txtID.Text
                         select new
                         {
                             ID = info.ID,
                             Name = info.Name,
                             Sex = info.Sex,
                             Age = info.Age,
                             Tel = info.Tel,
                             Address = info.Address,
                             QQ = info.QQ,
                             Email = info.Email
                         };
            //相应的文本框及下拉列表中显示选中员工的详细信息
            foreach (var item in result)
            {
                txtName.Text = item.Name;
                cboxSex.Text = item.Sex;
                txtAge.Text = item.Age.ToString();
                txtTel.Text = item.Tel;
                txtAddress.Text = item.Address;
                txtQQ.Text = item.QQ.ToString();
                txtEmail.Text = item.Email;
            }
        }

        private void btnEdit_Click(object sender, EventArgs e)
        {
            if (txtID.Text == "")
            {
                MessageBox.Show("请选择要修改的记录");
                return;
            }

            //实例化Linq连接对象
            linq = new linqtosqlClassDataContext(strCon);    
            //查找要修改的员工信息
            var result = from employee in linq.tb_Employee
                         where employee.ID == txtID.Text
                         select employee;
            //对指定的员工信息进行修改
            foreach (tb_Employee tbemployee in result)
            {
                tbemployee.Name = txtName.Text;
                tbemployee.Sex = cboxSex.Text;
                tbemployee.Age = Convert.ToInt32(txtAge.Text);
                tbemployee.Tel = txtTel.Text;
                tbemployee.Address = txtAddress.Text;
                tbemployee.QQ = txtQQ.Text;
                tbemployee.Email = txtEmail.Text;
                linq.SubmitChanges();
            }
            MessageBox.Show("员工信息修改成功");
            BindInfo();
        }

        #region 显示所有员工信息
        /// 
        /// 显示所有员工信息
        /// 
        private void BindInfo()
        {
            linq = new linqtosqlClassDataContext(strCon);//实例化Linq连接对象
            //获取所有员工信息
            var result = from info in linq.tb_Employee
                         select new
                         {
                             员工编号 = info.ID,
                             员工姓名 = info.Name,
                             性别 = info.Sex,
                             年龄 = info.Age,
                             电话 = info.Tel,
                             地址 = info.Address,
                             QQ = info.QQ,
                             Email = info.Email
                         };
            dgvInfo.DataSource = result;//对DataGridView控件进行数据绑定
        }
        #endregion

    }

C#学习之旅(四)_第18张图片
        (3)、删除数据:使用LINQ删除SQL Server数据库中的数据时,需要用到DeleteAllOnSubmit方法和SubmitChanges方法。
    DeleteAllOnSubmit方法用来将集合中的所有实体置于pending delete状态,其语法格式如下。
    void DeleteAllOnSubmit(IEnumerable entities)
    其中,entities表示要移除所有项的集合。
    插入以下代码,实现数据删除功能:

namespace Demo
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        //定义数据库连接字符串
        string strCon = "Data Source=服务器名称;Database=数据库名称;Uid=sa;Pwd=密码;";
        //声明Linq连接对象
        linqtosqlClassDataContext linq;
        //记录选中的员工编号
        string strID = "";

        private void Form1_Load(object sender, EventArgs e)
        {
            BindInfo();
        }

        private void dgvInfo_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            //获取选中的员工编号
            strID = Convert.ToString(dgvInfo[0, e.RowIndex].Value).Trim();
        }

        private void 删除ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (strID == "")
            {
                MessageBox.Show("请选择要删除的记录");
                return;
            }

            //实例化Linq连接对象
            linq = new linqtosqlClassDataContext(strCon);
            //查找要删除的员工信息
            var result = from employee in linq.tb_Employee
                         where employee.ID == strID
                         select employee;

            //删除员工信息
            linq.tb_Employee.DeleteAllOnSubmit(result);
            //实例化Linq连接对象提交操作
            linq.SubmitChanges();                       
            MessageBox.Show("员工信息删除成功");
            BindInfo();
        }

        #region 显示所有员工信息
        /// 
        /// 显示所有员工信息
        /// 
        private void BindInfo()
        {
            //实例化Linq连接对象
            linq = new linqtosqlClassDataContext(strCon);
            //获取所有员工信息
            var result = from info in linq.tb_Employee
                         select new
                         {
                             员工编号 = info.ID,
                             员工姓名 = info.Name,
                             性别 = info.Sex,
                             年龄 = info.Age,
                             电话 = info.Tel,
                             地址 = info.Address,
                             QQ = info.QQ,
                             Email = info.Email
                         };
            dgvInfo.DataSource = result;//对DataGridView控件进行数据绑定
        }
        #endregion
    }
}

C#学习之旅(四)_第19张图片

        2.3、LINQ操作其他数据

        2.3.1、使用LINQ操作数组和集合

        (1)、对数组和集合进行操作时可以使用LinqToObjects技术,它是一种新的处理集合的方法,如果采用旧方法,程序开发人员必须编写指定如何从集合检索数据的复杂的foreach循环,而采用LinqToObjects技术,只需编写描述要检索的内容的声明性代码。LinqToObjects能够直接使用LINQ查询IEnumerable或IEnumerable集合,而不需要使用LINQ提供程序或API,可以说,使用LINQ能够查询任何可枚举的集合,例如数组、泛型列表等。

C#学习之旅(四)_第20张图片

        2.3.2、使用LINQ操作DataSet数据集

        (1)、对DataSet数据集进行操作时可以使用LINQ to DataSet技术,它是LINQ to ADO.NET中的独立技术,使用LINQ to DataSet技术查询DataSet对象更加方便快捷,下面对LINQ to DataSet技术中常用到的方法进行详细讲解。
    ①、AsEnumerable方法
    AsEnumerable方法可以将DataTable对象转换为EnumerableRowCollection对象,其语法格式如下:
    public static EnumerableRowCollection AsEnumerable(this DataTable source)
    source:表示可枚举的源DataTable。
    返回值:一个IEnumerable对象,其泛型参数T为DataRow。

    ②、CopyToDataTable方法
    CopyToDataTable方法用来将IEnumerable对象中的数据赋值到DataTable对象中,其语法格式如下:
    public static DataTable CopyToDataTable(this IEnumerable source) where T : DataRow
    source:源IEnumerable序列。
    返回值:一个DataTable,其中包含作为DataRow对象的类型的输入序列。

    ③、AsDataView方法
    AsDataView方法用来创建并返回支持LINQ的DataView对象,其语法格式如下:
    public static DataView AsDataView(this EnumerableRowCollection source) where T : DataRow
    source:从中创建支持LINQ的DataView的源LINQ to DataSet查询。
    返回值:支持LINQ的DataView对象。

    ④、Take方法
    Take方法用来从序列的开头返回指定数量的连续元素,其语法格式如下:
    public static IEnumerable Take(this IEnumerable source,int count)
    source:表示要从其返回元素的序列。
    count:表示要返回的元素数量。
    返回值:一个IEnumerable,包含输入序列开头的指定数量的元素。

    ⑤、Sum方法
    Sum方法用来计算数值序列之和,其语法格式如下:
    public static decimal Sum(this IEnumerable source)
    source:一个要计算和的Decimal值序列。
    返回值:序列值之和。

    以上介绍的几种方法都有多种重载形式,这里只介绍了其常用的形式。

C#学习之旅(四)_第21张图片

        2.3.3、使用LINQ操作XML

        (1)、 对XML文件进行操作时可以使用LINQ to XML技术,它是LINQ技术中的一种,它提供了修改文档对象模型的内存文档,并支持LINQ查询表达式等功能,下面对LINQ to XML技术中常用到的方法进行详细讲解。
    ①、XElement类的Load方法
    Xelement类表示一个XML元素,其Load方法用来从文件加载Xelement,该方法语法格式如下:
    public static XElement Load(string uri)
    uri:一个URI字符串,用来引用要加载到新XElement中的文件。
    返回值:一个包含所指定文件的内容的XElement。

    ②、XElement类的SetAttributeValue方法
    SetAttributeValue方法用来设置属性的值、添加属性或移除属性,其语法格式如下:
    public void SetAttributeValue(XName name,Object value)
    name:一个XName,其中包含要更改的属性的名称。
    value:分配给属性的值。如果该值为null,则移除该属性;否则,会将值转换为其字符串表示形式,并分配给该属性的Value属性。

    ③、XElement类的Add方法
    Add方法用来将指定的内容添加为此XContainer的子级,其语法格式如下:
    public void Add(Object content)
    参数content表示要添加的包含简单内容的对象或内容对象集合。

    ④、XElement类的ReplaceNodes方法
    ReplaceNodes方法用来使用指定的内容替换此文档或元素的子节点,其语法格式如下:
    public void ReplaceNodes(Object content)
    参数content表示一个用于替换子节点的包含简单内容的对象或内容对象集合。

    ⑤、XElement类的Save方法
    Save方法用来序列化此元素的基础XML树,可以将输出保存到文件、XmlTextWriter、TextWriter或XmlWriter,其语法格式如下:
    public void Save(string fileName)
    参数fileName表示一个包含文件名称的字符串。

    ⑥、XDocument类的Save方法
    XDocument类表示XML文档,其Save方法用来将此XDocument序列化为文件、TextWriter或XmlWriter,该方法语法格式如下:
    public void Save(string fileName)
    参数fileName表示一个包含文件名称的字符串。

    ⑦、XDeclaration类
    XDeclaration类表示一个XML声明,其构造函数语法格式如下:
    public XDeclaration(string version,string encoding,string standalone)
    version:XML的版本,通常为“1.0”。
    encoding:XML文档的编码。
    standalone:包含“yes”或“no”的字符串,用来指定XML是独立的还是需要解析外部实体。

    使用LINQ to XML技术中的类时,需要添加System.Xml.Linq命名空间。

    插入以下代码实现对XML文档的增删改查。

namespace LinqOperXML
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        static string strPath = "Employee.xml";
        static string strID = "";

        //窗体加载时加载XML文件
        private void Form1_Load(object sender, EventArgs e)
        {
            getXmlInfo();
        }

        //添加XML元素
        private void button2_Click(object sender, EventArgs e)
        {
            //加载XML文档
            XElement xe = XElement.Load(strPath);
            //创建IEnumerable泛型结构
            IEnumerable<XElement> elements1 = from element in xe.Elements("People")
                                              select element;
            //生成新的编号
            string str = (Convert.ToInt32(elements1.Max(element => element.Attribute("ID").Value)) + 1).ToString("000");

            //创建XML元素
            XElement people = new XElement(
                "People", new XAttribute("ID", str),
                new XElement("Name", textBox11.Text),
                new XElement("Sex", comboBox1.Text),
                new XElement("Salary", textBox12.Text)
                );

            //添加XML元素
            xe.Add(people);
            //保存XML元素到XML文件
            xe.Save(strPath);
            getXmlInfo();
        }

        //修改XML元素
        private void button3_Click(object sender, EventArgs e)
        {
            //判断是否选择了编号
            if (strID != "")
            {
                //加载XML文档
                XElement xe = XElement.Load(strPath);
                IEnumerable<XElement> elements = from element in xe.Elements("People")
                                                 where element.Attribute("ID").Value == strID
                                                 select element;
                if (elements.Count() > 0)
                {
                    //获取找到的第一条记录
                    XElement newXE = elements.First();
                    //为XML元素设置属性
                    newXE.SetAttributeValue("ID", strID);
                    //替换XML元素中的值
                    newXE.ReplaceNodes(
                        new XElement("Name", textBox11.Text),
                        new XElement("Sex", comboBox1.Text),
                        new XElement("Salary", textBox12.Text)
                        );
                }

                //保存XML元素到XML文件中
                xe.Save(strPath);
            } 
            getXmlInfo();
        }

        //删除XML元素
        private void button4_Click(object sender, EventArgs e)
        {
            //判断是否选择了编号
            if (strID != "")
            {
                //加载XML文档
                XElement xe = XElement.Load(strPath);
                IEnumerable<XElement> elements = from element in xe.Elements("People")
                                                 where element.Attribute("ID").Value == strID
                                                 select element;
                //删除找到的XML元素信息
                if (elements.Count() > 0)
                    elements.First().Remove();
                xe.Save(strPath);
            }
            getXmlInfo();
        }

        //显示选中XML节点的详细信息
        private void dataGridView1_CellClick(object sender, DataGridViewCellEventArgs e)
        {
            //获取选中的ID编号
            strID = dataGridView1.Rows[e.RowIndex].Cells[3].Value.ToString();
            //加载XML文档
            XElement xe = XElement.Load(strPath);
            IEnumerable<XElement> elements = from PInfo in xe.Elements("People")
                                             where PInfo.Attribute("ID").Value == strID
                                             select PInfo;
            foreach (XElement element in elements)
            {
                textBox11.Text = element.Element("Name").Value;
                comboBox1.SelectedItem = element.Element("Sex").Value;
                textBox12.Text = element.Element("Salary").Value;
            }
        }

        #region 将XML文件内容绑定到DataGridView控件
        /// 
        /// 将XML文件内容绑定到DataGridView控件
        /// 
        private void getXmlInfo()
        {
            //创建DataSet数据集对象
            DataSet myds = new DataSet();
            //读取XML结构
            myds.ReadXml(strPath);
            //在DataGridView中显示XML文件中的信息
            dataGridView1.DataSource = myds.Tables[0];
        }
        #endregion
    }
}

C#学习之旅(四)_第22张图片
C#学习之旅(四)_第23张图片

        3、程序调试与异常处理

        开发应用程序的代码必须安全、准确。但是在编写的过程中,不可避免地会出现错误,而有的错误不容易别发觉,从而导致程序运行错误。为了排除这些非常隐蔽的错误,对编写好的代码要进行程序调试,这样才能确保应用程序能够成功运行。另外,开发程序时,不仅要注意程序代码的准确性和合理性,还要处理程序中可能出现的异常情况,.NET框架提供了一套称为结构化异常处理的标准错误机制,在这种机制中,如果出现错误或者任何预期之外的事件,都会引发异常。

        3.1、程序调试概述

         程序调试是在程序中查找错误的过程,在开发过程中,程序调试是检查代码并验证它能够正常运行的有效方法。另外,在开发时,如果发现程序不能正常工作,就必须找出并解决有关问题。
    在测试期间进行程序调试是很有用的,因为它对希望产生的代码结果提供了另外一级的验证。发布程序之后,程序调试提供了重新创建和检测程序错误的方法,程序调试可以帮助查找代码中的错误。
    程序调试就相当于组装完一辆汽车后,对其进行测试,检测一下油门、刹车、离合器、方向盘是否工作正常,如果发生异常,则需对其进行修改。

        3.2、常用的程序调试操作

         (1)、断点操作:
    断点是一个信号,它通知调试器在某个特定点上暂时将程序执行挂起。当执行在某个断点处挂起时,称程序处于中断模式。进入中断模式并不会终止或结束程序的执行。执行可以在任何时候继续。断点提供了一种强大的工具,能够在需要的时间和位置挂起执行。与逐句或逐条指令地检查代码不同的是,可以让程序一直执行,直到遇到断点,然后开始调试。这大大地加快了调试过程。没有这个功能,调试大的程序几乎是不可能的。
    插入断点有3中方式:
    ①、在要设置断点行旁边的灰色空白中单击

C#学习之旅(四)_第24张图片
        ②、右击设置断点的代码行,在弹出快捷菜单中选择“断点”—>“插入断点”命令

C#学习之旅(四)_第25张图片
        ③、单击要设置断点的代码行,选择菜单中的“调试”—>“切换断点(G)”命令

C#学习之旅(四)_第26张图片
        删除断点也有三种方式:
    ①、可以单击设置了断点的代码行左侧的红色原点
    ②、在设置了断点的行左侧的红色原点上右击,在弹出的快捷菜单中选择“删除断点”命令
    ③、在设置了断点的代码行上右击,在弹出的快捷菜单中选择“断点”—>“删除断点”命令

         (2)、开始执行:
    开始执行是最基本的调试功能之一,从“调试”菜单中选择“开始调试”命令或在代码中右击,可执行代码中的某行,然后从弹出的跨界菜单中选择“运行到光标处”命令。

C#学习之旅(四)_第27张图片
C#学习之旅(四)_第28张图片
        除了使用上述的方法开始执行外,还可以直接单击工具栏中的启动按钮,启动调试。

在这里插入图片描述
        如果选择“开始调试”命令,则应用程序启动并一直运行到断点。可以在任何时刻中断执行,以检查值,修改变量或检查程序状态。
    如果选择“运行到光标处”命令,则应用程序启动并一直运行到断点或光标位置,具体要看断点在前还是在光标在前,可以在源窗口中设置光标位置。如果光标在断点的前面,则代码首先运行到光标处。

         (3)、中断执行:
    当执行到达一个断点或发生异常,调试器将中断程序的执行。选择“调试”—>“全部中断”命令后,调试器将停止所有在调试器下运行的程序的执行。程序并不退出,可以随时恢复执行。

C#学习之旅(四)_第29张图片
         (4)、停止执行:
    停止执行意味着终止正在调试的进程并结束调试会话,可以通过选择菜单中的“调试”—>“停止调试”命令来结束运行和调试。也可以选择工具栏中的停止按钮执行。

在这里插入图片描述
         (5)、单步执行和逐过程执行:
     通过单步执行,调试器每次只执行一行代码。单步执行主要是通过逐语句、逐过程和跳出这3种命令实现的。“逐语句”和“逐过程”的主要区别是当某一行包含函数调用时,“逐语句”仅执行调用本身,然后在函数内的第一个代码行处停止。而“逐过程”执行整个函数,然后在函数外的第一行处停止。如果位于函数调用的内部并想返回到调用函数时,应使用“跳出”,“跳出”将一直执行代码,直到函数返回,然后在调用函数中的返回点处中断。

在这里插入图片描述
         除了在工具栏中单击这3个按钮外,还可以通过快捷键执行这3种操作,启动调试后,按F11键执行“逐语句”操作,按F10键执行“逐过程”操作以及按Shift + F10键执行“跳出”操作。

         (5)、运行到指定位置:
    如果希望程序运行到指定的位置,可以通过在指定代码行上单击鼠标右键,在弹出的快捷菜单中选择“运行到光标处”命令。这样,当程序运行到光标处时,会自动暂停。也可以在指定的位置插入断点,同样可以使程序运行到插入断点的代码行。关于如何插入断点和选择“运行到光标处”命令本章已经做过介绍,此处不再赘述。

        3.3、异常处理概述

         (1)、异常处理是一种功能强大的机制,用于处理应用程序可能产生的错误或是其他可以中断程序执行的异常情况。异常处理可以捕捉程序执行所发生的错误,通过异常处理可以有效、快速地构建各种用来处理程序异常情况的程序代码。
    在.NET类库中,提供了针对各种异常情形所涉及的异常类,这些类包含了异常的相关信息。配合异常处理语句,应用程序能够轻易地避免程序执行时可能中断应用程序的各种错误。

        (公共异常类及说明)

        3.4、异常处理语句

         (1)、try…catch语句:
    try…catch语句允许在try后面的大括号{}中放置可能发生异常情况的程序代码,对这些程序代码进行监控。在catch后面的大括号{}中则放置处理错误的程序代码,以处理程序发生的异常。try…catch语句的基本格式如下。
     try
    {
        被监控的代码
    }
    catch(异常类名 异常变量名)
    {
        异常处理
    }

C#学习之旅(四)_第30张图片
         查看运行结果,抛出了异常。因为声明的object变量obj被初始化为null,然后又将obj强制转换成int类型,这样就产生了异常,由于使用了try…catch语句,所以将这个异常铺货,并将异常输出。

C#学习之旅(四)_第31张图片
         (2)、 throw语句用于主动引发一个异常,使用throw语句可以在特定的情形下,自行抛出异常。throw语句的基本格式如下。
    throw ExObject
    ExObject:所要抛出的异常对象,这个异常对象是派生自System.Exception类的类对象。
    通常throw语句与try…catch或try…finally语句一起使用。当引发异常时,程序查找处理此异常的catch语句,也可以用throw语句重新引发以捕获的异常。

C#学习之旅(四)_第32张图片
         (3)、将finally语句与try…catch语句结合,形成try…catch…finally语句。finally语句同样以区块的方式存在,它被放在所有try…catch语句的最后面,程序执行完毕,最后都会跳到finally语句区块,执行其中的代码。
    try
    {
        被监控的代码
    }
    catch(异常类名 异常变量名)
    {
        异常处理
    }
    finally
    {
    程序代码
    }
    对于try…catch…finally语句的理解并不复杂,它只是比try…catch语句多了一个finally语句,如果程序中有一些在任何情形中都必须执行的代码,那么就可以将他们放在finally语句的区块中。
    使用catch子句是为了允许处理异常,无论是否引发了异常,使用finally子句即可执行清理代码,如果分配了昂贵或有限的资源(如数据库连接或流),则应将释放这些资源的代码放置在finally块中。

C#学习之旅(四)_第33张图片


DataGridViewSelectionMode枚举值及说明

枚举值 说明
cellSelect 可以选定一个或多个单元格
ColumnHeaderSelect 可以通过单击列的标头单元格选定此列,通过单击某个单元格可以单独选定此单元格
FullColumnSelect 通过单击列的标头或该列所包含的单元格选定整个列
FullRowSelect 通过单击行的标头或该行所包含的单元格选定整个行
RowHeaderSelect 通过单击行的标头单元格选定此行,通过单击某个单元格可以单独选定此单元格



公共异常类及说明

异常类 说明
System.ArithmeticException 在算术运算期间发生的异常
System.ArrayTypeMismatchException 当存储一个数组时,如果由于被存储的元素的实际类型与数组的实际类型不兼容而导致存储失败,就会引发此异常
System.DivideByZeroException 在试图用零除整数值时引发
System.IndexOutOfRangeException 在试图使用小于零或超出数组界限的下标索引数组时引发
System.InvalidCastException 当从基类型或接口到派生类型的显示转换在运行时失败,就会引发此异常
System.NullReferenceException 在需要使用引用对象的场合,如果使用null引用,就会引发此异常
System.OutOfMemoryException 在分配内存的尝试失败时引发
System.OutflowException 在选中的上下文中所进行的算术运算、类型转换或操作导致溢出是引发的异常
System.StackOverflowException 挂起的方法调用过多而导致执行堆栈溢出时引发的异常
System.TypeInitializationException 在静态构造函数引发异常并且没有可以捕捉到它的catch子句时引发

你可能感兴趣的:(C#专栏,c#,windows,microsoft)