C# WPF 数据绑定实战:将 DataSet 数据转化为界面信息
本文旨在演示如何在 C# WPF 应用程序中实现数据绑定,将底层数据集(DataSet)转化为直观的用户界面信息。
结果或目标
我们需要构建一个包含两个主要部分的应用程序界面:上方显示“客户”和“订单”的具体录入信息,下方分别以列表形式展示所有已添加的客户数据和订单数据。界面上的文本框应与输入字段双向绑定,而下方的列表视图(ListView)应能自动反映后台数据库的变化。核心目标是通过声明式的 XAML 语法将逻辑与界面分离,并验证 DataSet 中的父子表关系及计算列能否正确传递给 UI。
准备条件
本示例基于 .NET Framework 环境下的 Windows Presentation Foundation (WPF) 技术。需要创建一个包含主窗口(MainWindow)的 WPF 项目。UI 布局将通过 Grid、GroupBox 和 TextBox 等标准控件实现。数据层将使用 ADO.NET 的 DataSet 对象来模拟数据仓库,其中包含具有主外键关系的表以及用于汇总计算的派生列。
真实操作顺序
第1步:设计主界面的 XAML 结构
首先定义窗口的整体布局。我们使用一个主 Grid 容器划分四个行:Row 0 为客户信息组,Row 1 为订单信息组,Row 2 为客户列表展示区,Row 3 为订单列表展示区。为了更清晰地理解最终生成的界面效果,请参考以下运行后的界面截图:
第2步:配置客户信息组的控件与绑定
在第一个 GroupBox 内部,创建网格以便对齐标签与输入框。为了实现数据绑定,关键在于设置 Text 属性的 Binding 标记扩展。例如,用于输入客户编号的 TextBox,其 Text 属性绑定到数据源的 CID 路径;同理,客户名称绑定到 Name 路径。这种绑定模式不仅实现了数据显示,还允许用户在控件内修改数据后反向更新数据源。
XAML 代码片段:
<GroupBox Header="Customer" Grid.Row="0" Padding="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!-- 标签 -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="CustomerID" Margin="2" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<!-- 绑定至 CID 属性 -->
<TextBox Grid.Row="0" Grid.Column="1" Margin="2" Name="tbxCustomerID" Text="{Binding Path=CID}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="CustomerName" Margin="2" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<!-- 绑定至 Name 属性 -->
<TextBox Grid.Row="1" Grid.Column="1" Margin="2" Name="tbxCustomerName" Text="{Binding Path=Name}"/>
<!-- 添加按钮,触发事件 -->
<Button Grid.Row="2" Grid.Column="1" Content="Add New Customer" Margin="2" Name="btnAddCustomer" Padding="2" Click="btnAddCustomer_Click" />
</Grid>
</GroupBox>
第3步:配置订单信息组的控件与绑定
订单信息组的布局逻辑与客户组类似。我们在 Grid.Row="1" 的区域定义订单的明细字段。重点在于建立多个输入项与后端字段的对应关系:OrderID 绑定 OID,OrderName(此处指代客户关联名或订单名)绑定 Customer 字段,Subtotal 绑定 Subtotal,TaxRate 绑定 TaxRate。同样需要一个按钮触发后续的数据处理逻辑。
XAML 代码片段:
<GroupBox Header="Order" Grid.Row="1" Padding="5">
<Grid>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Text="OrderID" Margin="2" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBox Grid.Row="0" Grid.Column="1" Margin="2" Name="tbxOrderID" Text="{Binding Path=OID}"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="OrderName" Margin="2" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBox Grid.Row="1" Grid.Column="1" Margin="2" Name="tbxOrderName" Text="{Binding Path=Customer}"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="Subtotal" Margin="2" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBox Grid.Row="2" Grid.Column="1" Margin="2" Name="tbxSubtotal" Text="{Binding Path=Subtotal}"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="TaxRate" Margin="2" HorizontalAlignment="Right" VerticalAlignment="Center"/>
<TextBox Grid.Row="3" Grid.Column="1" Margin="2" Name="tbxTaxRate" Text="{Binding Path=TaxRate}"/>
<Button Grid.Row="4" Grid.Column="1" Content="Add New Order" Margin="2" Name="btnAddOrder" Padding="2" Click="btnAddOrder_Click" />
</Grid>
</GroupBox>
第4步:配置底部列表视图的数据呈现
为了将分散的数据整合展示,我们使用两个 ListView 控件。它们位于底部的两行中。关键点在于 ItemsSource 属性设置为 {Binding},这意味着列表将从其父级 DataContext 获取集合数据。
此外,为了美化表格显示,我们为每个 ListView 定义了 GridView 视图,并为每一列指定 DisplayMemberBinding 以显示对应的数据字段(如客户的总金额、订单的含税总额等)。
XAML 代码片段:
<ListView Name="lstDisplayCustomer" ItemsSource="{Binding}" Grid.Row="2" Margin="2" MinHeight="150">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="CustomerID" DisplayMemberBinding="{Binding CID}"/>
<GridViewColumn Header="CustomerName" DisplayMemberBinding="{Binding Name}"/>
<!-- 显示子表的聚合数据 -->
<GridViewColumn Header="Total" DisplayMemberBinding="{Binding OrderTotals}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
<ListView Name="lstDisplayOrder" ItemsSource="{Binding}" Grid.Row="3" Margin="2" MinHeight="150">
<ListView.View>
<GridView>
<GridView.Columns>
<GridViewColumn Header="OrderID" DisplayMemberBinding="{Binding OID}"/>
<GridViewColumn Header="Customer" DisplayMemberBinding="{Binding Customer}"/>
<GridViewColumn Header="Subtotal" DisplayMemberBinding="{Binding Subtotal}"/>
<GridViewColumn Header="TaxRate" DisplayMemberBinding="{Binding TaxRate}" />
<GridViewColumn Header="Total" DisplayMemberBinding="{Binding Total}" />
</GridView.Columns>
</GridView>
</ListView.View>
</ListView>
第5步:编写 C# 后端逻辑建立数据模型
在 Code-Behind 文件中,我们需要构建并初始化数据上下文。这里采用一个静态方法 NewData 来生成示例用的 DataSet。
- 构建父表(客户表): 实例化
DataTable,添加 ID 和姓名列。 - 构建子表(订单表): 实例化另一个
DataTable,包含订单 ID、客户 ID(外键)、金额和税率。 - 建立关系与计算:
- 将两张表加入同一个
DataSet。 - 通过
Relations.Add建立CID(客户ID)到Customer(订单客户ID)的主外键关系。 - 在客户表中添加一个计算列
OrderTotals,使用表达式Sum(Child.Total)。这将使得每个客户数据自带其名下所有订单总额的统计结果。 - 在订单表中添加一列
Total,使用表达式Subtotal*(1+TaxRate)进行实时计算。
- 将两张表加入同一个
C# 代码逻辑:
// 全局变量或类成员
DataSet business = new DataSet(); // 实际应在构造函数或Init中初始化
private static DataSet NewData()
{
// 1. build the parent table and add some data
DataTable customer = new DataTable("Customer");
customer.Columns.Add("CID", typeof(Int32));
customer.Columns.Add("Name", typeof(string));
// 2. build the child table and add some data.
DataTable orders = new DataTable("Order");
orders.Columns.Add("OID", typeof(int));
orders.Columns.Add("Customer", typeof(Int32));
orders.Columns.Add("Subtotal", typeof(decimal));
orders.Columns.Add("TaxRate", typeof(decimal));
// 计算列:小计 * (1 + 税率)
orders.Columns.Add("Total",typeof(decimal),"Subtotal*(1+TaxRate)");
// 3. Link the table within a Dataset.
business = new DataSet();
business.Tables.Add(customer);
business.Tables.Add(orders);
// 建立主外键关系,便于跨表查询和聚合
business.Relations.Add(customer.Columns["CID"], orders.Columns["Customer"]);
// 4. 在父表中添加聚合列,引用子表数据的总和
customer.Columns.Add("OrderTotals", typeof(decimal), "Sum(Child.Total)");
return business;
}
第6步:响应按钮点击并刷新数据上下文
当用户点击“Add New Customer”时,程序需要读取文本框的值,将其转换为新行数据插入到 customer 表中,然后重新绑定 DataContext 以确保下方的 ListView 能够刷新看到新记录。对于订单,逻辑完全一致,只是操作的是 orders 表。
C# 交互逻辑:
private void btnAddCustomer_Click(object sender, RoutedEventArgs e)
{
// 访问客户表数据源
DataTable customer = business.Tables["Customer"];
AddCustomerToTable(customer); // 提取出的通用方法
// 关键步骤:将当前数据表赋给 ListView 的 DataContext
lstDisplayCustomer.DataContext = customer;
}
// 通用辅助方法:从UI取值并追加到表
private DataTable AddCustomerToTable(DataTable table)
{
DataRow newRow = table.NewRow();
newRow["CID"] = tbxCustomerID.Text;
newRow["Name"] = tbxCustomerName.Text;
table.Rows.Add(newRow);
return table;
}
// 同理处理订单
private DataTable AddOrderToTable(DataTable table)
{
DataRow newRow = table.NewRow();
newRow["OID"] = tbxOrderID.Text;
newRow["Customer"] = tbxOrderName.Text; // 注意:原代码此处对应tbxOrderName,需确保数据类型匹配
newRow["Subtotal"] = tbxSubtotal.Text;
newRow["TaxRate"] = tbxTaxRate.Text;
table.Rows.Add(newRow);
return table;
}
private void btnAddOrder_Click(object sender, RoutedEventArgs e)
{
// 访问订单表数据源
DataTable order = business.Tables["Order"];
AddOrderToTable(order);
// 关键步骤:刷新订单列表视图
lstDisplayOrder.DataContext = order;
}
完成判断
程序启动后,若界面上方出现清晰的输入框和按钮,下方则显示带有“CustomerID”、“CustomerName”、“Total”等列头的空白表格。尝试在上方输入框填入数值(如 CID: 1, Name: Alice, Subtotal: 100),点击按钮后,若下方列表区域成功渲染出该条记录,且系统按照设定规则自动计算了相应的 Total 值和子表聚合值,则说明数据绑定流程已正确打通,原始数据已成功转化为可视化的界面信息。
简要总结
本示例展示了 WPF 的强大之处——通过声明式的绑定机制简化了繁琐的 UI 刷新逻辑。利用 DataSet 内置的关系引擎和表达式功能,我们可以轻松地在数据结构层处理复杂的层级与计算,而无需手动维护多张表格间的同步。开发者只需关注 DataContext 的设置与 XAML 属性映射即可实现高效的数据可视化。以上就是 C# WPF 数据绑定之数据转化为信息的详细内容,更多关于 C# WPF 编程的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









