社交俱乐部:使用 WinForms、C#.NET、ADO.NET 和 MS Access 的示例应用程序
使用 C#、ADO.NET 和 MS Access 开发的 WinForms 应用程序
目录
引言
本文介绍了一个使用 C# 开发的简单 Windows 数据库应用程序。它使用 WinForms 作为前端 (UI),MS Access 作为后端 (DB)。该应用程序名为“社交俱乐部”,用于创建和管理俱乐部成员的信息。
该应用程序的用户界面 (UI) 包含几个屏幕 (登录、注册、管理)。注册屏幕用于创建/注册新的俱乐部会员。管理屏幕提供了编辑、删除、搜索、打印俱乐部成员信息和导出数据到 Excel 的选项。本文将重点介绍如何在示例演示项目中应用某些主题;例如 3 层架构、连接到 Access 数据库、为 Access 数据库创建基本 SQL 语句、编写 ADO.NET 代码、使用 WinForms 和 C#.NET 实现 CURD 操作。
软件环境
应用程序在以下软件环境中开发
- 开发环境:Visual Studio.NET 2010
- 框架:.NET Framework 4.0
- 用户界面:Windows Forms
- 编程语言:C#.NET
- 数据访问:ADO.NET
- 数据库:MS Access 2010
- 代码分析工具:Stylecop
先决条件
您需要在您的机器上安装以下工具才能运行示例应用程序。
- Microsoft Visual Studio 2010
- Microsoft Access 2010
分层架构
表示层
表示层 (桌面) 是最顶层的,包含应用程序的用户界面。此层负责将信息传递给用户和应用程序。它包含用于用户交互的窗体 (UI) 和用于处理事件的代码隐藏 (UI 逻辑)。
数据层
数据层是中间层,包含业务服务方法、数据访问逻辑、数据模型和 SQL 脚本。
业务服务
业务服务包含与数据访问通信的方法。它充当表示逻辑和数据访问逻辑之间的桥梁。此层负责调用数据访问方法并将结果返回给表示层。
Data Model
数据模型包含反映数据的属性;这通常称为实体/业务对象。
SQL 脚本
SQL 脚本包含承载数据库逻辑的 SQL 语句。
数据访问
数据访问通常包含访问数据库数据的逻辑,并且通常在单独的类库项目中实现。在演示项目中,业务服务和数据访问实现在同一个类库中。
数据库层
数据库层包含具有表结构和数据的数据库。
项目结构
解决方案资源管理器显示了项目内的目录结构。解决方案包含两个项目。
桌面 (Windows 项目)
桌面项目是一个 Windows Forms 应用程序项目,包含窗体 (UI) 和相应的代码隐藏 (.CS) 文件。代码隐藏文件包含处理事件的 UI 逻辑。
数据 (库项目)
数据项目是一个类库项目,包含数据库逻辑 (SQL 脚本)、数据访问逻辑 (ADO.NET 代码) 和数据模型 (业务实体)。所有服务方法和与数据相关的逻辑都驻留在同一个类库中。在多层架构系统中,最好将这些分别放在单独的类库项目中,并在需要时将库项目引用到相应的项目中。
以这种方式组织文件夹、文件、项目可以将代码分成不同的部分,使每个部分处理不同的关注点。这是将程序分成部分的原则。这使得代码可重用、可读、易于管理和维护。
创建数据库
社交俱乐部应用程序只需要一个表来存储俱乐部成员信息。下面显示的图像显示了设计视图中的数据库。它显示了左侧面板中的表以及右侧面板中的详细信息 (字段名称、数据类型、描述)。可以通过右侧面板下方的“常规”选项卡设置每个字段的属性。
以下是在 MS Access 2010 中创建数据库的步骤
- 打开 MS Access 并单击“空白数据库”模板 (这将打开一个新的空白数据库,左侧面板中有一个默认表“Table1”。
- 右键单击表并转到设计视图 (将弹出一个小窗口要求保存表)
- 为表命名 (在本例中,表名为“ClubMember”),然后单击“保存”。
- 创建具有必要数据类型、属性和描述的字段 (列)。
- 5. 在“文件”菜单中单击“另存为”选项,然后通过提供适当的名称保存数据库 (在本例中,数据库名称为“SocialClub”)。数据库将另存为 {filename}.accdb 文件。
设置项目
我假设您对 Visual Studio 环境有一定的了解。在此我将列出设置桌面和数据项目的步骤。
- 打开 Visual Studio,选择 文件 -> 新建 -> 项目
- 在新建项目窗口中,从“其他项目类型”模板中选择“Visual Studio 解决方案”
- 将项目名称命名为“SocialClub”,然后单击“确定”。
- 右键单击解决方案,然后选择 添加 -> 新建项目
- 在新建项目窗口中,从模板中选择 Visual C# -> Windows -> Windows Forms 应用程序
- 将项目名称命名为“SocialClub.Desktop”,然后单击“确定”。
- 再次右键单击解决方案,然后选择 添加 -> 新建项目
- 在新建项目窗口中,从模板中选择 Visual C# -> Windows -> 类库
- 将项目名称命名为“SocialClub.Data”,然后单击“确定”。
- 在“SocialClub.Desktop”项目中,右键单击“引用”,然后选择“添加引用”。
- 在“添加引用”窗口中,选择“项目”选项卡 -> SocialClub.Data 项目,然后单击“确定”。
- 按 CTRL+SHFT+B 并检查应用程序是否可以生成。
- 将数据库文件 (SocialClub.accdb) 复制到应用程序启动路径下的 bin 目录。
现在,您已在 Visual Studio 中设置了项目,并准备开始编码。下面是步骤 11 的 Visual Studio 屏幕截图。
实现数据层
命名常量 (枚举)
为字段 (健康状况、婚姻状况、职业) 创建了一组命名常量 (枚举)。数据库中的这些字段将包含枚举值的数字等效项,并且数据模型中的这些字段将是相应的枚举类型。此外,这些枚举值 (字符串等效值) 将显示在 UI 的下拉列表中供选择。
类图
示例代码
/// <summary>
/// Enum for Health status
/// </summary>
public enum HealthStatus
{
Excellent = 1,
Good,
Average,
Poor
}
/// <summary>
/// Enum for Marital status
/// </summary>
public enum MaritalStatus
{
Married = 1,
Single
}
/// <summary>
/// Enum for Occupation
/// </summary>
public enum Occupation
{
Doctor = 1,
Engineer,
Professor,
}
数据模型 (实体)
我们需要在项目中拥有业务实体/模型,该模型将包含反映数据库表中字段的属性。此实体将用作数据传输对象 (DTO),仅用于在层之间传输数据。下面显示了为示例应用程序创建的数据模型。
类图
代码
/// <summary>
/// ClubMemberModel class
/// </summary>
public class ClubMemberModel
{
/// <summary>
/// Gets or sets member id
/// </summary>
public int Id { get; set; }
/// <summary>
/// Gets or sets member name
/// </summary>
public string Name { get; set; }
/// <summary>
/// Gets or sets date of birth
/// </summary>
public DateTime DateOfBirth { get; set; }
/// <summary>
/// Gets or sets occupation
/// </summary>
public Occupation Occupation { get; set; }
/// <summary>
/// Gets or sets marital status
/// </summary>
public MaritalStatus MaritalStatus { get; set; }
/// <summary>
/// Gets or sets health status
/// </summary>
public HealthStatus HealthStatus { get; set; }
/// <summary>
/// Gets or sets salary
/// </summary>
public decimal Salary { get; set; }
/// <summary>
/// Gets or sets number of children
/// </summary>
public int NumberOfChildren { get; set; }
}
连接字符串
连接字符串包含有关提供程序和数据源的信息。ACE OLDB 12.0 提供程序用于连接到 Access 数据库。此连接字符串会传递到数据访问代码中,以便 ADO.NET 对象可以与数据库建立连接。
存储连接字符串
通常,数据库连接字符串会存储在 CONFIG 文件中,以便于配置,并从中访问。要将连接字符串存储在配置文件中,请按照以下步骤操作:
- 右键单击“SocialClub.Desktop”项目,选择 添加 -> 新建项
- 在“添加新项”窗口中,选择 Visual C# 项 -> 常规 -> 应用程序配置文件,然后单击“确定” (app.config 将添加到项目中)。
- 在 app.config 中,添加以下代码
<configuration>
<connectionStrings>
<add name="SocialClubDBConnection"
connectionString="Provider=Microsoft.ACE.OLEDB.12.0;
Data Source=|DataDirectory|\SocialClub.accdb;Persist Security Info=True"
providerName="System.Data.OleDb" />
</connectionStrings>
</configuration>
访问连接字符串
ConfigurationManager
类提供对配置文件的访问。可以通过 ConfigurationManager
访问 app.config 中的连接字符串。在演示项目中,这是通过创建一个名为 ConnectionAccess
的抽象类来完成的,该类包含一个名为 ConnectionString
的属性,该属性返回存储在配置文件中的连接字符串。代码如下:
using System.Configuration;
/// <summary>
/// ConnectionAccess class
/// </summary>
public abstract class ConnectionAccess
{
/// <summary>
/// Gets connection string
/// </summary>
protected string ConnectionString
{
get
{
return ConfigurationManager
.ConnectionStrings["SocialClubDBConnection"]
.ToString();
}
}
}
为 MS Access 创建 SQL 语句
由于应用程序包含 CURD 操作,因此我们需要以下可以针对 Access 数据库执行的 SQL 语句:
- SELECT
- SELECT (按输入参数)
- INSERT
- 更新
- 删除
所有必需的 SQL 语句都已添加到一个静态类中,作为只读字符串并被访问。
类图
代码:静态类中的 SQL 脚本
/// <summary>
/// DBConstants static class contains sql string constants
/// </summary>
public static class Scripts
{
/// <summary>
/// Sql to get a club member details by Id
/// </summary>
public static readonly string sqlGetClubMemberById = "Select" +
" Id, Name, DateOfBirth, Occupation, MaritalStatus, " +
"HealthStatus, Salary, NumberOfChildren" +
" From ClubMember Where Id = @Id";
/// <summary>
/// Sql to get all club members
/// </summary>
public static readonly string SqlGetAllClubMembers = "Select" +
" Id, Name, DateOfBirth, Occupation, MaritalStatus, " +
"HealthStatus, Salary, NumberOfChildren" +
" From ClubMember";
/// <summary>
/// sql to insert a club member details
/// </summary>
public static readonly string SqlInsertClubMember = "Insert Into" +
" ClubMember(Name, DateOfBirth, Occupation," +
" MaritalStatus, HealthStatus, Salary, NumberOfChildren)" +
" Values(@Name, @DateOfBirth, @Occupation, " +
"@MaritalStatus, @HealthStatus, @Salary, @NumberOfChildren)";
/// <summary>
/// sql to search for club members
/// </summary>
public static readonly string SqlSearchClubMembers = "Select " +
" Id, Name, DateOfBirth, Occupation, MaritalStatus, " +
"HealthStatus, Salary, NumberOfChildren" +
" From ClubMember Where (@Occupation Is NULL OR @Occupation = Occupation) {0}" +
" (@MaritalStatus Is NULL OR @MaritalStatus = MaritalStatus)";
/// <summary>
/// sql to update club member details
/// </summary>
public static readonly string sqlUpdateClubMember = "Update ClubMember " +
" Set [Name] = @Name, [DateOfBirth] = @DateOfBirth, " +
"[Occupation] = @Occupation, [MaritalStatus] = @MaritalStatus, " +
" [HealthStatus] = @HealthStatus, [Salary] = @Salary, " +
"[NumberOfChildren] = @NumberOfChildren Where ([Id] = @Id)";
/// <summary>
/// sql to delete a club member record
/// </summary>
public static readonly string sqlDeleteClubMember = "Delete From ClubMember Where (Id = @Id)";
}
使用 ADO.NET 编写数据访问
ADO.NET 是 .NET Framework 附带的数据访问技术之一。它包含一组类,为 .NET 应用程序提供数据访问服务。我将带您了解 ADO.NET 对象的一些基础知识,这些对象用于数据库通信以及加载和修改数据的步骤。
ADO.NET 对象
连接对象
Connection 对象用于在应用程序和数据库之间创建连接。
命令对象
Command 对象用于存储需要针对数据库执行的 SQL 语句。Command 对象可以执行 SELECT、INSERT、UPDATE、DELETE、存储过程。
DataReader 对象
DataReader
对象用于从数据库检索数据。DataReader
对象是一种仅向前、只读的游标类型,它提供了一种更快地从数据库检索记录的方法。
DataAdapter 对象
DataAdapter
对象用于从数据库检索数据并将数据填充到 DataTable
或 DataSet
中。DataSet
是数据库的内存表示,包含 DataTable
集合。DataAdapter
对象使用 Fill 方法将数据填充到 DataSet
中。它使用连接对象和命令对象自动打开连接、执行命令并关闭连接。
使用 DataAdapter 加载数据的步骤
- 创建
DataAdapter
对象的实例 - 将 Command 对象的新实例分配给 DataAdapter 的
SelectCommand
属性 - 设置
SelectCommand
的连接和 Command 属性 - 将 (任何) 参数添加到 SelectCommand 的
ParameterCollection
中 - 调用
DataAdapter
对象的 Fill 方法,并将DataTable
对象传递给它。
使用这些 ADO.NET 对象取决于数据源。MS Access 是 OLE DB 数据源。连接到 OLEDB 数据源时,我们需要在 System.Data.OleDb
命名空间中使用 OleDbConnection
和 OleDdCommand
。
示例代码
// Create new instance of dataadapter object
OleDbDataAdapter oleDbDataAdapter = new OleDbDataAdapter()
// Create the command and set its properties
oleDbDataAdapter.SelectCommand = new OleDbCommand();
oleDbDataAdapter.SelectCommand.Connection = new OleDbConnection(this.ConnectionString);
oleDbDataAdapter.SelectCommand.CommandType = CommandType.Text;
// Assign the SQL to the command object
oleDbDataAdapter.SelectCommand.CommandText = Scripts.SqlGetAllClubMembers;
// Fill the datatable from adapter
oleDbDataAdapter.Fill(dataTable);
使用 Command 对象修改数据的步骤
- 创建一个新的 Command 对象实例
- 设置 Command 对象的连接属性
- 将 Command 对象的 CommandType 属性设置为 Text
- 通过设置 CommandText 属性将 SQL 语句放入 Command 对象中
- 将输入参数添加到 Command 对象的参数集合属性中
- 打开连接
- 通过调用命令对象上的
ExecuteNonQuery
方法来执行命令 - 关闭连接
示例代码
// Create a new instance of command object
OleDbCommand dbCommand = new OleDbCommand()
// Set the command object properties
dbCommand.Connection = new OleDbConnection(this.ConnectionString);
dbCommand.CommandType = CommandType.Text;
dbCommand.CommandText = Scripts.sqlUpdateClubMember;
// Add the input parameters to the parameter collection
dbCommand.Parameters.AddWithValue("@Name", clubMember.Name);
//..
dbCommand.Parameters.AddWithValue("@Id", clubMember.Id);
// Open the connection, execute the query and close the connection
dbCommand.Connection.Open();
var rowsAffected = dbCommand.ExecuteNonQuery();
dbCommand.Connection.Close();
在将输入参数添加到参数集合时,请确保按照 SQL 语句中的顺序添加参数。
类图和数据访问代码
数据访问代码
using System;
using System.Data;
using System.Data.OleDb;
using John.SocialClub.Data.DataModel;
using John.SocialClub.Data.Sql;
/// <summary>
/// Data access class for ClubMember table
/// </summary>
public class ClubMemberAccess : ConnectionAccess, IClubMemberAccess
{
/// <summary>
/// Method to get all club members
/// </summary>
/// <returns>Data table</returns>
public DataTable GetAllClubMembers()
{
DataTable dataTable = new DataTable();
using (OleDbDataAdapter oleDbDataAdapter = new OleDbDataAdapter())
{
// Create the command and set its properties
oleDbDataAdapter.SelectCommand = new OleDbCommand();
oleDbDataAdapter.SelectCommand.Connection = new OleDbConnection(this.ConnectionString);
oleDbDataAdapter.SelectCommand.CommandType = CommandType.Text;
// Assign the SQL to the command object
oleDbDataAdapter.SelectCommand.CommandText = Scripts.SqlGetAllClubMembers;
// Fill the datatable from adapter
oleDbDataAdapter.Fill(dataTable);
}
return dataTable;
}
/// <summary>
/// Method to get club member by Id
/// </summary>
/// <param name="id">member id</param>
/// <returns>Data row</returns>
public DataRow GetClubMemberById(int id)
{
DataTable dataTable = new DataTable();
DataRow dataRow;
using (OleDbDataAdapter dataAdapter = new OleDbDataAdapter())
{
// Create the command and set its properties
dataAdapter.SelectCommand = new OleDbCommand();
dataAdapter.SelectCommand.Connection = new OleDbConnection(this.ConnectionString);
dataAdapter.SelectCommand.CommandType = CommandType.Text;
dataAdapter.SelectCommand.CommandText = Scripts.sqlGetClubMemberById;
// Add the parameter to the parameter collection
dataAdapter.SelectCommand.Parameters.AddWithValue("@Id", id);
// Fill the datatable From adapter
dataAdapter.Fill(dataTable);
// Get the datarow from the table
dataRow = dataTable.Rows.Count > 0 ? dataTable.Rows[0] : null;
return dataRow;
}
}
/// <summary>
/// Method to search club members by multiple parameters
/// </summary>
/// <param name="occupation">occupation value</param>
/// <param name="maritalStatus">marital status</param>
/// <param name="operand">AND OR operand</param>
/// <returns>Data table</returns>
public DataTable SearchClubMembers(object occupation, object maritalStatus, string operand)
{
DataTable dataTable = new DataTable();
using (OleDbDataAdapter oleDbDataAdapter = new OleDbDataAdapter())
{
// Create the command and set its properties
oleDbDataAdapter.SelectCommand = new OleDbCommand();
oleDbDataAdapter.SelectCommand.Connection =
new OleDbConnection(this.ConnectionString);
oleDbDataAdapter.SelectCommand.CommandType = CommandType.Text;
// Assign the SQL to the command object
oleDbDataAdapter.SelectCommand.CommandText =
string.Format(Scripts.SqlSearchClubMembers, operand);
// Add the input parameters to the parameter collection
oleDbDataAdapter.SelectCommand.Parameters.AddWithValue(
"@Occupation",
occupation == null ? DBNull.Value : occupation);
oleDbDataAdapter.SelectCommand.Parameters.AddWithValue(
"@MaritalStatus",
maritalStatus == null ? DBNull.Value : maritalStatus);
// Fill the table from adapter
oleDbDataAdapter.Fill(dataTable);
}
return dataTable;
}
/// <summary>
/// Method to add new member
/// </summary>
/// <param name="clubMember">club member model</param>
/// <returns>true or false</returns>
public bool AddClubMember(ClubMemberModel clubMember)
{
using (OleDbCommand oleDbCommand = new OleDbCommand())
{
// Set the command object properties
oleDbCommand.Connection = new OleDbConnection(this.ConnectionString);
oleDbCommand.CommandType = CommandType.Text;
oleDbCommand.CommandText = Scripts.SqlInsertClubMember;
// Add the input parameters to the parameter collection
oleDbCommand.Parameters.AddWithValue("@Name", clubMember.Name);
oleDbCommand.Parameters.AddWithValue("@DateOfBirth",
clubMember.DateOfBirth.ToShortDateString());
oleDbCommand.Parameters.AddWithValue("@Occupation",
(int)clubMember.Occupation);
oleDbCommand.Parameters.AddWithValue("@MaritalStatus",
(int)clubMember.MaritalStatus);
oleDbCommand.Parameters.AddWithValue("@HealthStatus",
(int)clubMember.HealthStatus);
oleDbCommand.Parameters.AddWithValue("@Salary", clubMember.Salary);
oleDbCommand.Parameters.AddWithValue("@NumberOfChildren",
clubMember.NumberOfChildren);
// Open the connection, execute the query and close the connection
oleDbCommand.Connection.Open();
var rowsAffected = oleDbCommand.ExecuteNonQuery();
oleDbCommand.Connection.Close();
return rowsAffected > 0;
}
}
/// <summary>
/// Method to update club member
/// </summary>
/// <param name="clubMember">club member</param>
/// <returns>true / false</returns>
public bool UpdateClubMember(ClubMemberModel clubMember)
{
using (OleDbCommand dbCommand = new OleDbCommand())
{
// Set the command object properties
dbCommand.Connection = new OleDbConnection(this.ConnectionString);
dbCommand.CommandType = CommandType.Text;
dbCommand.CommandText = Scripts.sqlUpdateClubMember;
// Add the input parameters to the parameter collection
dbCommand.Parameters.AddWithValue("@Name", clubMember.Name);
dbCommand.Parameters.AddWithValue("@DateOfBirth",
clubMember.DateOfBirth.ToShortDateString());
dbCommand.Parameters.AddWithValue("@Occupation",
(int)clubMember.Occupation);
dbCommand.Parameters.AddWithValue("@MaritalStatus",
(int)clubMember.MaritalStatus);
dbCommand.Parameters.AddWithValue("@HealthStatus",
(int)clubMember.HealthStatus);
dbCommand.Parameters.AddWithValue("@Salary", clubMember.Salary);
dbCommand.Parameters.AddWithValue("@NumberOfChildren",
clubMember.NumberOfChildren);
dbCommand.Parameters.AddWithValue("@Id", clubMember.Id);
// Open the connection, execute the query and close the connection
dbCommand.Connection.Open();
var rowsAffected = dbCommand.ExecuteNonQuery();
dbCommand.Connection.Close();
return rowsAffected > 0;
}
}
/// <summary>
/// Method to delete a club member
/// </summary>
/// <param name="id">member id</param>
/// <returns>true / false</returns>
public bool DeleteClubMember(int id)
{
using (OleDbCommand dbCommand = new OleDbCommand())
{
// Set the command object properties
dbCommand.Connection = new OleDbConnection(this.ConnectionString);
dbCommand.CommandType = CommandType.Text;
dbCommand.CommandText = Scripts.sqlDeleteClubMember;
// Add the input parameter to the parameter collection
dbCommand.Parameters.AddWithValue("@Id", id);
// Open the connection, execute the query and close the connection
dbCommand.Connection.Open();
var rowsAffected = dbCommand.ExecuteNonQuery();
dbCommand.Connection.Close();
return rowsAffected > 0;
}
}
}
业务服务类
服务类充当数据访问和 UI 之间的桥梁。它包含调用数据访问方法的服务方法。
类图
代码:服务类
/// <summary>
/// Service class to query the DataAccess, implements IClubMemberService interface
/// </summary>
public class ClubMemberService : IClubMemberService
{
/// <summary>
/// interface of ClubMemberAccess
/// </summary>
private IClubMemberAccess memberAccess;
/// <summary>
/// Initializes a new instance of the ClubMemberService class
/// </summary>
public ClubMemberService()
{
this.memberAccess = new ClubMemberAccess();
}
/// <summary>
/// Service method to get club member by Id
/// </summary>
/// <param name="id">member id</param>
/// <returns>Data row</returns>
public DataRow GetClubMemberById(int id)
{
// call to Data access method to get club member by id
return this.memberAccess.GetClubMemberById(id);
}
/// <summary>
/// Service method to get all club members
/// </summary>
/// <returns>Data table</returns>
public DataTable GetAllClubMembers()
{
// call to Data access method to get all club members
return this.memberAccess.GetAllClubMembers();
}
/// <summary>
/// Service method to search records by multiple parameters
/// </summary>
/// <param name="occupation">occupation value</param>
/// <param name="maritalStatus">marital status</param>
/// <param name="operand">AND OR operand</param>
/// <returns>Data table</returns>
public DataTable SearchClubMembers(object occupation, object maritalStatus, string operand)
{
// Call to data access method with search parameters
return this.memberAccess.SearchClubMembers(occupation, maritalStatus, operand);
}
/// <summary>
/// Service method to create new member
/// </summary>
/// <param name="clubMember">club member model</param>
/// <returns>true or false</returns>
public bool RegisterClubMember(ClubMemberModel clubMember)
{
// Call to data access method to add club member details
return this.memberAccess.AddClubMember(clubMember);
}
/// <summary>
/// Service method to update club member
/// </summary>
/// <param name="clubMember">club member</param>
/// <returns>true / false</returns>
public bool UpdateClubMember(ClubMemberModel clubMember)
{
// Call to data access method to update club member details
return this.memberAccess.UpdateClubMember(clubMember);
}
/// <summary>
/// Method to delete a club member
/// </summary>
/// <param name="id">member id</param>
/// <returns>true / false</returns>
public bool DeleteClubMember(int id)
{
// Call to data access method to delete a member
return this.memberAccess.DeleteClubMember(id);
}
}
桌面:UI (窗体) 和事件
窗体是 WinForms 应用程序的基本单元。因此,设计用户界面的方式非常重要。.NET Framework 提供了丰富的控件来设计窗体,Visual Studio IDE 在设计窗体 (使用其拖放功能) 和编写控件事件代码方面提供了出色的支持。在演示项目中,我们有以下屏幕:
登录
一个简单的登录屏幕,包含控件 (标签、文本框和按钮),用于接受用户名和密码。按钮单击事件在代码隐藏中处理。凭据 (用户名、密码) 存储在设置中,通用消息、文本存储在资源文件中。在桌面项目中,展开“属性”节点,然后双击“设置/资源”以修改/检查详细信息。
登录示例代码:按钮单击事件
/// <summary>
/// Click event to handle the login process
/// </summary>
/// <param name="sender">sender object</param>
/// <param name="e">event data</param>
private void Login_Click(object sender, EventArgs e)
{
if (txtUsername.Text.Trim() == Settings.Default.Username &&
txtPassword.Text.Trim() == Settings.Default.Password)
{
var frmManage = new Manage();
frmManage.Show();
this.Hide();
}
else
{
MessageBox.Show(
Resources.Login_Validation_Message,
Resources.Login_Validation_Message_Title,
MessageBoxButtons.OK,
MessageBoxIcon.Information);
}
}
注册
注册屏幕提供输入俱乐部成员信息的界面。屏幕截图和代码示例如下所示。
注册示例代码:按钮单击事件
/// <summary>
/// Click event to handle registration
/// </summary>
/// <param name="sender">sender object</param>
/// <param name="e">event data</param>
private void Register_Click(object sender, EventArgs e)
{
try
{
// Check if the validation passes
if (this.ValidateRegistration())
{
// Assign the values to the model
ClubMemberModel clubMemberModel = new ClubMemberModel()
{
Id = 0,
Name = txtName.Text.Trim(),
DateOfBirth = dtDateOfBirth.Value,
Occupation = (Occupation)cmbOccupation.SelectedValue,
HealthStatus = (HealthStatus)cmbHealthStatus.SelectedValue,
MaritalStatus = (MaritalStatus)cmbMaritalStatus.SelectedValue,
Salary = txtSalary.Text.Trim() ==
string.Empty ? 0 : Convert.ToDecimal(txtSalary.Text),
NumberOfChildren = txtNoOfChildren.Text.Trim() ==
string.Empty ? 0 : Convert.ToInt16(txtNoOfChildren.Text)
};
// Call the service method and assign the return status to variable
var success = this.clubMemberService.RegisterClubMember(clubMemberModel);
// if status of success variable is true then display
// a information else display the error message
if (success)
{
// display the message box
MessageBox.Show(
Resources.Registration_Successful_Message,
Resources.Registration_Successful_Message_Title,
MessageBoxButtons.OK,
MessageBoxIcon.Information);
// Reset the screen
this.ResetRegistration();
}
else
{
// display the error messge
MessageBox.Show(
Resources.Registration_Error_Message,
Resources.Registration_Error_Message_Title,
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
else
{
// Display the validation failed message
MessageBox.Show(
this.errorMessage,
Resources.Registration_Error_Message_Title,
MessageBoxButtons.OK,
MessageBoxIcon.Error);
}
}
catch (Exception ex)
{
this.ShowErrorMessage(ex);
}
}
搜索和管理
搜索和管理屏幕提供简单的搜索功能,并允许用户选择、更新、删除、打印和导出成员详细信息。一个轻量级类库“DataGridViewPrinter.dll”用于实现“打印”功能。该库取自此处。您可以参考该文章了解打印预览和打印功能是如何实现的。搜索和管理屏幕和一些示例代码如下所示。
示例代码:搜索按钮单击事件
/// <summary>
/// Click event to handle search
/// </summary>
/// <param name="sender">sender object</param>
/// <param name="e">event data</param>
private void Search_Click(object sender, EventArgs e)
{
try
{
// Call to service method by passing the selected search paramters
DataTable data = this.clubMemberService.SearchClubMembers(
cmbSearchOccupation.SelectedValue,
cmbSearchMaritalStatus.SelectedValue,
cmbOperand.GetItemText(cmbOperand.SelectedItem)
);
// Call to private method by passing the result set to load the grid view
this.LoadDataGridView(data);
}
catch (Exception ex)
{
this.ShowErrorMessage(ex);
}
}
/// <summary>
/// Method to load data grid view
/// </summary>
/// <param name="data">data table</param>
private void LoadDataGridView(DataTable data)
{
// Setting the data source and table for data grid view to display the data
dataGridViewMembers.DataSource = data;
dataGridViewMembers.DataMember = data.TableName;
dataGridViewMembers.AutoResizeColumns(DataGridViewAutoSizeColumnsMode.AllCells);
}
结论
我介绍了使用 C# WinForms 连接到 MS Access、编写 ADO.NET 代码和应用 3 层模式的一些内容。希望您喜欢阅读本文。