使用单个输入控件的主从解决方案
展示了一种使用文本框创建主从关系的解决方案。
引言
这是我在这里的第一篇文章,尽管我曾多次利用这个伟大网站上的丰富知识。所以请耐心阅读。
**这是一个免责声明,让大家知道无论我了解多少,我总是在学习!!!所以评论、提问、抱怨都会被愉快地接受!!!**
问题
本文旨在解决的问题是,使用单个输入控件(如 TextBox
、DateTimePicker
等)创建数据的“主-从”视图,而不是使用多个输入控件(如 ComboBox
和 ListBox
)。
这是我试图实现的一个快速预览。这是在当前显示的 DataGrid
中选择一行之前的程序状态:
这是在当前显示的 DataGrid
中选择一行之后的程序状态:
基本上,该程序根据其合作对象和具体日期,从数据库中提取一份工作列表。当用户选择一个已安排的工作(那些没有标题的是程序为安排生成的空白工作,并且在主从关系中被忽略)时,左侧和下方 DataGrid
的 TextBox
会更新以显示选定的工作和客户信息。
这是用于填充 DataGrid
的简化存储过程:
GetJobByDateAndArtist (@ArtistID bigint, @Date datetime)
AS
SELECT
Job.JobStartTime, Job.JobTitle, Job.ClientID
FROM
Job
WHERE
Job.ArtistID = @ArtistID AND Jobs.JobDate = @Date
以下是用于填充 TextBox
的存储过程:
这是用于客户文本框的:
GetClientInfoByID(@ClientID bigint)
AS
SELECT
*
FROM
Clients
WHERE
Clients.ClientID = @ClientID
这是用于工作详情文本框的:
GetAJobsDetails(@JobID bigint)
AS
SELECT
*
FROM
Job
WHERE
Job.JobID = @JobID
到目前为止,我遇到的所有主从关系解决方案都涉及到将客户列在一个 datagrid 或列表控件中,然后有一个第二个 datagrid 显示选定客户的预约。它们通常只是在数据集中设置一个关系,然后程序就会处理其余的事情。
问题是,在我的程序中,工作是用户最想看到的项目,而用户只希望看到所选工作的客户详情。
为了最大限度地减少系统负载,程序被设计为一次只提取一个客户记录。
现在,尽管 Customers 表实际上是 Job 表的父表,但 Job datagrid 是程序的主要焦点,使用 Relationships 似乎只会导致我的代码崩溃。
解决方案
首先,我们设置一些初步工作,包括:
- 添加三个单独的
SqlDataAdapter
(一个用于工作,一个用于客户信息,一个用于工作详情)。 - 生成一个强类型数据集(VS 自动化太棒了!)。
- 添加一个
DataView
对象(用于排序目的)并将其链接到DataSet
的 GetJobsByArtistAndDate 表。 - 添加一个
DataGrid
控件,并将DataSource
属性链接到DataView
对象。 - 添加
TextBox
控件,并将其 DataBindings 链接到DataSet
中 GetClientInfoByID 和 GetAJobDetails 表的相应列。
现在开始编写一些功能代码。
接下来,我使用 VS 为我的 Appointments DataGrid
创建了一个 MouseDown
事件处理程序。
这是完成后的方法的样子:
private void WeeklyDataGrids_MouseDown(object sender, System.Windows.Forms.MouseEventArgs e)
{
if (((DataGrid)sender).HitTest(e.X,e.Y).Row >= 0)
{
this.dataSet11.GetAJobDetails.Clear();
this.dataSet11.GetClientInfoByID.Clear();
if (((double)this.CurrentDailyDataView[((DataGrid)
sender).HitTest(e.X,e.Y).Row]["JobTotalHours"]) != 0)
{
this.GetClientByIDSqlDataAdapter.SelectCommand.Parameters["@ClientID"].Value =
this.CurrentDailyDataView[(
(DataGrid)sender).HitTest(e.X,e.Y).Row]["ClientID"].ToString();
this.GetClientByIDSqlDataAdapter.Fill(this.dataSet11.GetClientInfoByID);
this.GetJobDetailsSqlDataAdapter.SelectCommand.Parameters["@JobID"].Value =
this.CurrentDailyDataView[(
(DataGrid)sender).HitTest(e.X,e.Y).Row]["JobID"].ToString();
this.GetJobDetailsSqlDataAdapter.Fill(this.dataSet11.GetAJobDetails);
}
}
}
详细说明
我想重点介绍这个方法的一些关键点。
if (((DataGrid)sender).HitTest(e.X,e.Y).Row >= 0)
第一行简单地测试以确保我们没有选择 DataGrid
的列标题。
this.dataSet11.GetAJobDetails.Clear();
this.dataSet11.GetClientInfoByID.Clear();
这两行是最重要的,因为 TextBox
控件和其他单个输入控件会自动绑定到 DataTable
的第一个可用记录。如果我们从不清除内存中的表,该方法将继续添加我们想要的记录,但仍然显示我们选择的第一条记录。
if (((double)this.CurrentDailyDataView[(
(DataGrid)sender).HitTest(e.X,e.Y).Row]["JobTotalHours"]) != 0)
程序会自动使用未安排的工作槽填充 DataView
对象(链接到 DataSet
的 GetJobsByArtistAndDate 表)。如果我们刚刚选择了一个未安排的工作,返回的 JobID 将不会匹配数据库中的当前工作,并会导致代码崩溃。此“if
”测试通过检查当前选定记录的 JobTotalHour 列是否不为零(换句话说,它是一项已安排的工作)来防止这种情况。
this.GetClientByIDSqlDataAdapter.SelectCommand.Parameters["@ClientID"].Value =
this.CurrentDailyDataView[((DataGrid)sender).HitTest(e.X,e.Y).Row]["ClientID"].ToString();
并且
this.GetJobDetailsSqlDataAdapter.SelectCommand.Parameters["@JobID"].Value =
this.CurrentDailyDataView[((DataGrid)sender).HitTest(e.X,e.Y).Row]["JobID"].ToString();
上面的两个代码片段都做了同样的事情。它们都使用 DataView
中对应于活动 DataGrid
的选定行的 DataRow
的相应列来填充 GetClientDetailsByID
和 GetJobDetails
的 SelectCommand
参数。
((DataGrid)sender)
这个小代码片段是我称之为“智能编码”的东西,它可以为您节省一些时间并减少您需要编写的代码量。基本上,它所做的就是将方法的 sender
参数强制转换为 DataGrid
对象,这使得我们可以访问 DataGrid
对象的任何属性(因为我们知道发送事件的是一个 DataGrid
)。
这做了一件非常重要的事情,因为我的程序实际上包含 10 个不同的 DataGrid
,代表两个人每周的工作日,并且每个工作日的工作都加载到每个 DataGrid
中。如果我使用
Person1MondayJobsDataGrid.HitTest(e.X,e.Y)
这对于 person 1 的周一工作的 DataGrid
将会正常工作,但是其他 9 个 DataGrid
都需要有自己的事件处理程序(那就是 54 行不必要的代码!!)。通过将 sender
变量强制转换为 DataGrid
类型,我可以为我需要此功能的每个 DataGrid
重用相同的事件处理程序。
结论
为了使用文本框或其他单个输入控件创建主从关系,需要一个单独的 DataTable
,并且每次选择主 DataGrid
上的记录时,都必须清除 DataTable
并仅填充一条记录,这样文本框才能绑定到正确的记录。
历史
- 2005 年 11 月 25 日 - 发布文章。
- 2005 年 11 月 29 日 - 添加了屏幕截图。
- 2005 年 11 月 29 日 - 修改了代码以使用
DataView
对象绑定到DataGrid
控件。 - 2005 年 11 月 29 日 - 将
DataGrid
控件捕获的事件从CurrentCellChanged
事件更改为MouseDown
事件(响应更快)。 - 2005 年 11 月 29 日 - 修复了文章文本中的问题。
- 2005 年 11 月 29 日 - 重新组织了每个部分,以便更好地解释问题、解决方案和细节。
- 2005 年 11 月 29 日 - 删除了文章中任何不必要的内容(感谢 John)。
- 2005 年 11 月 29 日 - 添加了历史记录部分。