#程序员##万众创业##IT教育##.net##IT#
动态列在动态表显示时非常有用,常见的DataGrid显示时,xaml里静态指定了列名和列属性,而动态列是通过代码加列,在列名是动态时,比较有用。本例子来自于codeproject,经过锐英源的详细翻译,供大家学习,有些细节因为有闲暇巴盗用不能公布,有兴趣的请关注联系锐英源,锐英源有专业的开源企业服务。
介绍
Datagrid控件非常适合显示存储在表格中的数据。数据库表中的一行等于数据 格中的一行。当数据存储在多个表中时,比如表 A 和 B,并且行 A 与表 B 中的行具有一对多(也称为 1:N、父子或主从)关系,则行 A 可以引用表 B 中的多行。这种类型的数据可以在主从数据视图类型中显示。另一种类型的数据关系是多对多类型(也称为 N:M 关系)。表A的行可以对表B的行有多个引用。但是除了前面的情况,表B的一行可以被表A的多行引用。
使用代码
应用程序
示例代码实现了一个用户管理表单,可以在其中管理用户、角色和用户角色分配。角色和用户显示在两个数据 格中。用户角色分配在用户数据 格中完成。因此,此 格具有动态内容,将每个角色显示为单独的复选框列。通过选中相应的复选框来完成用户角色分配。
数据模型
这个样本的数据模型由一个User和一个Role表组成,一个UserRole表是其他两个表之间的关联表。表中的条目UserRole意味着用户(由其用户 id 引用)具有分配的角色(由角色的 id 引用)。如果某个用户-角色组合没有条目,则意味着相关用户没有分配相应的角色。
数据模型是使用 .NET 实现的DataSet。它是一个具有引用完整性的良好内存数据库,它包含发布数据行的插入、删除和修改的内置通知委托。它的内容可以存储到一个 XML 文件中,在本例中用作持久性机制。
组件和类图
下一个组件图显示了应用程序的分层:
应用
视图模型
数据模型
执行
数据绑定
该应用程序是使用 MVVM 设计模式编写的。这意味着主窗口绑定到主视图模型,视图控件绑定到主视图模型的属性。
参考 |
查看控件属性 |
ViewModel 属性 |
1 |
MainWindow:DataGridRoles.ItemsSource |
MainViewModel.Roles |
2 |
MainWindow:DataGridUsers.ItemsSource |
MainViewModel.Users |
3 |
MainWindow:DataGridUsers.Column |
MainViewModel.UserRoleColumns |
要点1:将数据库角色表绑定到角色数据 格控件
要点2:将数据库用户表绑定到用户数据 格控件
要点 3:将列的可观察集合绑定到用户 格控件的列属性。动态列行为是通过此属性实现的,因为视图模型中的逻辑在此集合中添加和删除列。
注:要点。
<Window x:Class="Application.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:attachedBehaviors="clr-namespace:Application.AttachedBehaviors" xmlns:viewModel="clr-namespace:ViewModel;assembly=ViewModel" Title="User Administration" Height="350" Width="525"> <Window.DataContext> <viewModel:MainViewModel/> </Window.DataContext> <DockPanel LastChildFill="True"> <ToolBar DockPanel.Dock="Top"> <Button Content="Save" Command="{Binding SaveCommand}"/> </ToolBar> <Grid> <Grid.RowDefinitions> <RowDefinition Height="146*"/> <RowDefinition Height="147*"/> </Grid.RowDefinitions> <GroupBox x:Name="UsersGroupBox" Grid.Column="0" Header="User Role Assignment"> <DataGrid x:Name="DataGridUsers" ItemsSource="{Binding Users}" attachedBehaviors:DataGridColumnsBehavior.BindableColumns= "{Binding UserRoleColumns}" AutoGenerateColumns="False" EnableRowVirtualization="False"/> </GroupBox> <GroupBox x:Name="RolesGroupBox" Grid.Row="1" Grid.Column="0" Header="Roles"> <DataGrid x:Name="DataGridRoles" ItemsSource="{Binding Roles}" AutoGenerateColumns="False"> <DataGrid.Columns> <DataGridTextColumn Header="Name" Binding="{Binding Name}"/> </DataGrid.Columns> </DataGrid> </GroupBox> </Grid> </DockPanel> </Window>
数据处理
数据保存在UserRoleDataSet(Role、User和RoleUser)中的三个表中。Role和User表通过DataView 绑定到数据 格控件。允许修改、插入和删除行以及阻止这些操作。DataView上也可以过滤和排序。数据 格控件可以使用DataView控制数据. 可以在数据 格控件中插入、修改和删除行( 格底部有一个新的项目行,按下删除键时删除行),通过DataView可以直接更新数据。
C#
public class MainViewModel{ public MainViewModel() { --- Code omitted --- this.UserRoleColumns = new ObservableCollection<DataGridColumn>();
--- Code omitted --- } public DataView Users { get { return this.dataContext.DataSet.User.DefaultView; } } public DataView Roles { get { return this.dataContext.DataSet.Role.DefaultView; } } public ObservableCollection UserRoleColumns { get; private set; }}
DataSet可以与数据库连接一起使用,以从 SQL 服务器等存储和检索数据。在这个应用程序中,我使用持久性机制在 XML 文件中存储和检索数据。
每个DataSet表都有一组事件,可用于在数据修改时获得通知。此机制用于在修改角色表时添加、删除和更新动态列。
C#
public class MainViewModel{ public MainViewModel() { --- Code omitted --- this.dataContext = DatabaseContext.Instance; this.dataContext.DataSet.Role.RoleRowChanged += this.RoleOnRowChanged; this.dataContext.DataSet.Role.RoleRowDeleted += this.RoleOnRoleRowDeleted; --- Code omitted --- } private void RoleOnRowChanged(object sender, UserRoleDataSet.RoleRowChangeEvent roleRowChangeEvent) { switch (roleRowChangeEvent.Action) { case DataRowAction.Change: this.UpdateRoleColumn(roleRowChangeEvent.Row); break; case DataRowAction.Add: this.AddRoleColumn(roleRowChangeEvent.Row); break; } } private void RoleOnRoleRowDeleted(object sender, UserRoleDataSet.RoleRowChangeEvent roleRowChangeEvent) { if (roleRowChangeEvent.Action == DataRowAction.Delete) { this.DeleteRoleColumn(roleRowChangeEvent.Row); } }}
商业逻辑
默认列定义
用户数据 格列定义存储在UserRolesColumns集合中。这意味着默认列,用户的名字和姓氏,也必须在此集合中。DataGridTextColumns为名字和姓氏实例化了两个,单元格内容通过绑定到行的各自字段来绑定到数据行。
C#
public class MainViewModel{ public MainViewModel() { this.GenerateDefaultColumns(); --- Code omitted --- } private void GenerateDefaultColumns() { this.UserRoleColumns.Add(new DataGridTextColumn { Header = "First Name", Binding = new Binding("FirstName") }); this.UserRoleColumns.Add(new DataGridTextColumn { Header = "Last Name", Binding = new Binding("LastName") }); }}
动态列定义
动态列处理分为 3 种操作类型:
C#
public class MainViewModel{ private void AddRoleColumn(UserRoleDataSet.RoleRow role) { var resourceDictionary = ResourceDictionaryResolver.GetResourceDictionary("Styles.xaml"); var userRoleValueConverter = resourceDictionary["UserRoleValueConverter"] as IValueConverter; var checkBoxColumnStyle = resourceDictionary["CheckBoxColumnStyle"] as Style; var binding = new Binding { Converter = userRoleValueConverter, RelativeSource = new RelativeSource(RelativeSourceMode.FindAncestor, typeof(DataGridCell), 1), Path = new PropertyPath("."), Mode = BindingMode.TwoWay }; var dataGridCheckBoxColumn = new DataGridCheckBoxColumn { Header = role.Name, Binding = binding, IsThreeState = false, CanUserSort = false, ElementStyle = checkBoxColumnStyle, }; ObjectTag.SetTag(dataGridCheckBoxColumn, role); this.UserRoleColumns.Add(dataGridCheckBoxColumn); } private void UpdateRoleColumn(UserRoleDataSet.RoleRow role) { if (role != null) { foreach (var userRoleColumn in this.UserRoleColumns) { var roleScan = ColumnTag.GetTag(userRoleColumn) as UserRoleDataSet.RoleRow; if (roleScan == role) { userRoleColumn.Header = role.Name; break; } } } } private void DeleteRoleColumn(UserRoleDataSet.RoleRow role) { if (role != null) { foreach (var userRoleColumn in this.UserRoleColumns) { var roleScan = ColumnTag.GetTag(userRoleColumn) as UserRoleDataSet.RoleRow; if (roleScan == role) { this.UserRoleColumns.Remove(userRoleColumn); break; } } } }}
用户角色分配
将DataGridCheckBoxColumn复选框控件绑定到它正在显示的行中数据的(可为空的)布尔属性。在这种情况下,它将是用户数据行中的布尔属性,表示用户到角色分配。由于定义中没有这样的属性,因此UserTable必须实施另一种解决方案。不是绑定到复选框控件,而是实例化一个值转换器并将其绑定到DataGridCell将包含该控件的CheckBox控件。上面显示的方法中的Binding定义AddRoleColumn包含对值转换器的赋值。绑定控件的相对源设置为DataGridCell,作为CheckBox控件的祖先找到(绑定在CheckBox级别上定义)。
Convert每次DataGrid最初修改单元格或失去焦点时,都会调用值转换器的方法。在这两种情况下,都会检索用户和角色角色并返回转换结果(如果用户具有分配的角色)。用户行从DataGridCell’s中获取DataContext,其中包含DataRowView在其Row属性中具有用户行的实例。角色是从ColumnTag添加时分配给列的 中检索的。
C#
public class UserRoleValueConverter : IValueConverter{ public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { bool result = false; var dataGridCell = value as DataGridCell; if (dataGridCell != null) { var dataRowView = dataGridCell.DataContext as DataRowView; if (dataRowView != null) { var user = dataRowView.Row as UserRoleDataSet.UserRow; var role = ColumnTag.GetTag(dataGridCell.Column) as UserRoleDataSet.RoleRow; if (user != null && role != null) { var checkBox = dataGridCell.Content as CheckBox; if (checkBox != null) { if (dataGridCell.IsEditing) { checkBox.Checked += this.CheckBoxOnChecked; } else { checkBox.Checked -= this.CheckBoxOnChecked; } } result = DatabaseContext.Instance.DataSet.UserRole.Any( x => x.UserRow == user && x.RoleRow == role); } } } return result; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); }
CheckedBoxOnChecked每当修改复选框状态时,都会调用该方法。逻辑搜索CheckBox’sDataGridCell并获取属于它的用户和角色实例。它将根据CheckBox.IsChecked状态以及 UserRoleRow是否已经存在来添加或删除用户角色条目。
C#
private void CheckBoxOnChecked(object sender, RoutedEventArgs routedEventArgs) { var checkBox = sender as CheckBox; var dataGridCell = ControlHelper.FindVisualParent(checkBox); if (dataGridCell != null) { var dataRowView = dataGridCell.DataContext as DataRowView; if (checkBox != null && dataRowView != null) { var user = dataRowView.Row as UserRoleDataSet.UserRow; var role = ObjectTag.GetTag(dataGridCell.Column) as UserRoleDataSet.RoleRow; if (user != null && role != null) { if (checkBox.IsChecked == true && DatabaseContext.Instance.DataSet.UserRole.Any( x => x.UserRow == user && x.RoleRow == role) == false) { DatabaseContext.Instance.DataSet.UserRole.AddUserRoleRow(user, role); } else { var userRole = DatabaseContext.Instance.DataSet.UserRole.FirstOrDefault( x => x.UserRow == user && x.RoleRow == role); if (userRole != null) { userRole.Delete(); } } } } } }}
兴趣点
结论
声明:本站部分文章及图片源自用户投稿,如本站任何资料有侵权请您尽早请联系jinwei@zod.com.cn进行处理,非常感谢!