循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(10) -- 在DataGrid上直接编辑保存数据
有时候,一些数据的录入可能需要使用表格直接录入会显得更加方便快捷,这种情况有时候也是由于客户使用习惯而提出,本篇随笔介绍在WPF应用端上使用DataGrid来直接新增、编辑、保存数据的处理。
录入数据的时候,我们都采用在一个窗体界面中,根据不同内容进行录入,但是有时候涉及主从表的数据录入,从表的数据有时候为了录入方便,也会通过表格控件直接录入。在Winform开发的时候,我们很多时候可以利用表格GridControl控件来直接录入数据;在BS的Vue&Elment前端项目中,也可以利用第三方组件vxe-table直接录入表格数据。
在不同的前端处理中,对于数据直接录入的处理,我写了一些随笔,可以参考。
在Winform界面中,也可以实现基于表格数据的直接录入,如下随笔所示《在DevExpress程序中使用Winform分页控件直接录入数据并保存》、《在DevExpress程序中使用GridView直接录入数据的时候,增加列表选择的功能》、《在Winform中直接录入表格数据和在Vue&Elment中直接录入表格数据的比较》。
如在Vue的前端录入中,也可以实现数据直接录入的,详细可以参考随笔介绍《在Vue前端界面中,几种数据表格的展示处理,以及表格编辑录入处理操作》。
在Bootstrap的Web开发中,也可以使用控件实现数据表格的直接录入处理,如随笔介绍《在Bootstrap开发框架中使用dataTable直接录入表格行数据》。
1、在DataGrid上直接编辑保存数据的界面效果
一般情况下,我们可能会利用新的窗口来承载数据表格的内容,这样展现的方式会比较灵活,也比较丰富一些,如下界面所示。
有时候,我们也会采用直接录入数据的方式,来快速直接录入一些简单的数据,如下界面所示。
对于新增或者编辑,单击某行记录的时候,会进行编辑处理,如下界面所示。
但是,往往很多数据不是简单的录入,我们可能会涉及一些下拉列表,以及一些自定义的处理,如下所示。
普通下拉列表的处理
也可能是一些特殊的自定义处理,如选择图标的操作。
当然还有一些单选框、复选框等处理,那些也是类似处理,不在赘述。
2、实现过程和思路
大致了解了一些常规的直接编辑处理,我们来看看如何具体实现上面的效果的。
一般默认的DataGrid就是可以编辑内容的,或者你把只读属性IsReadOnly设置为false即可,如下: IsReadOnly="False"
编辑情况下,我们列表就不用设置复选框来勾选,而采用序号显示的方式,如下设置代码。
<DataGrid x:Name="grid" hc:DataGridAttach.ShowRowNumber="True" AddingNewItem="grid_AddingNewItem" AutoGenerateColumns="False" CanUserAddRows="True" CanUserSortColumns="False" GridLinesVisibility="Vertical" HeadersVisibility="All" ItemsSource="{Binding ViewModel.MenuItems, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" RowHeaderWidth="60" SelectionMode="Extended" VerticalGridLinesBrush="AliceBlue"> <!--<DataGrid.RowHeaderTemplate> <DataTemplate> <CheckBox IsChecked="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=DataGridRow}}" /> </DataTemplate> </DataGrid.RowHeaderTemplate>-->
对于直接编辑的数据列表,需要采用ObservableCollection<T>的集合处理,如果采用List<T>是不可以正常处理的。
/// <summary> /// 编辑的数据列表 /// </summary> [ObservableProperty] private ObservableCollection<MenuInfo>? menuItems;
定义好集合后,我们对其中任何记录的处理,都是可以反映到界面上的了。如果需要新增记录,我们添加一个新的记录到上面的集合中即可体现到界面上了。
例如我们通过按钮新增一条记录,触发一个命令处理即可。
<Button Width="80" Height="40" Margin="5" hc:IconElement.Geometry="{StaticResource AddGeometry}" Command="{Binding AddNewCommand}" Content="新增" Style="{StaticResource ButtonInfo}" />
其中AddNewCommand的命令操作,就是往上面的集合中添加一个记录即可体现到界面上了。
/// <summary> /// 新增记录 /// </summary> [RelayCommand] private void AddNew() { this.ViewModel!.MenuItems!.Add(new MenuInfo() { SystemType_ID = App.ViewModel.SystemType, //初始化 }); }
界面效果如下所示。
一般的列,编辑状态下就是文本框的处理,如下代码所示。
<DataGrid.Columns> <DataGridTextColumn MinWidth="50" Binding="{Binding Name}" Header="显示名称" />
而如果要自定义常规显示和编辑状态下的不同,那么就需要自定义模板<DataGridTemplateColumn.CellTemplate>、<DataGridTemplateColumn.CellEditingTemplate>来处理,如下所示。
例如对于图标列,两个模板内容不同的。
<DataGridTemplateColumn Width="80" Header="图标"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <ui:SymbolIcon Width="32" FontSize="32" Symbol="{Binding Icon}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <StackPanel MinWidth="200" Background="{DynamicResource RegionBrush}" Orientation="Horizontal"> <ui:SymbolIcon FontSize="24" Foreground="red" Symbol="{Binding Icon, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> <Button Command="{Binding Path=DataContext.SelectIconCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=DataGrid}, Path=SelectedItem}" Content="选择图标" Foreground="red" Style="{StaticResource ButtonInfo.Small}" /> </StackPanel> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn>
编辑模板下的显示和常规的不一样,以便提供一些入口我们进行相应的处理。
这里通过按钮,触发一个选择图标的命令操作,如下代码所示。
/// <summary> /// 选择图标 /// </summary> [RelayCommand] private void SelectIcon(MenuInfo info) { //基于 SymbolRegular 图标选择 var page = App.GetService<SymbolRegularSelectPage>(); page!.ViewModel.ResetData();//每次更新数据 if (page.ShowDialog() == true) { var item = page.ViewModel.SelectedItem; info.Icon = item.Text; } }
而对于一些普通的下拉列表,我们通过提供数据源的方式来绑定列表即可。
根据实际情况初始化下拉列表的内容,如下所示。
/// <summary> /// 初始化字典 /// </summary> /// <returns></returns> public async Task InitDictItem() { //初始化性别的列表 this.GenderItems = new List<CListItem>() { new("男"), new("女") }; this.IsExpandToYesNoItems = new List<CListItem>() { new() { Text="是", Value = "1"}, new() { Text="否", Value = "0"}, }; this.IsVisibleToYesNoItems = new List<CListItem>() { new() { Text="是", Value = "1"}, new() { Text="否", Value = "0"}, }; }
其中XAML中的下拉列表的处理代码如下所示。
<DataGridTemplateColumn Width="100" Header="是否可见"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Foreground="{Binding Visible, Converter={StaticResource NumberToColorReConverter}}" Text="{Binding Visible, Converter={StaticResource NumberToYesNoStrConverter}}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <ComboBox ItemsSource="{Binding DataContext.ViewModel.IsVisibleToYesNoItems, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type DataGrid}}}" SelectedValue="{Binding Visible, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" SelectedValuePath="Value" Text="{Binding Visible, UpdateSourceTrigger=PropertyChanged, Converter={StaticResource NumberToYesNoStrConverter}}" /> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn>
注意上面的绑定和选择路径,从而可以通过修改直接反映到集合上。
其中获取记录集合的处理操作代码如下所示。
public override async Task GetData() { //转换下分页信息 ConvertPagingInfo(); var result = await service.GetListAsync(this.PageDto); if (result != null) { //this.MenuItems.Clear(); this.MenuItems = new ObservableCollection<MenuInfo>(result.Items?.ToList()); this.PagerInfo.RecordCount = result.TotalCount; } }
通过获得查询数据的处理,我们可以显示具体的页面信息。
<StackPanel Orientation="Horizontal"> <hc:Pagination Margin="0,10,0,10" DataCountPerPage="{Binding ViewModel.PagerInfo.PageSize}" IsJumpEnabled="True" MaxPageCount="{Binding ViewModel.PagerInfo.MaxPageCount}" MaxPageInterval="5" PageIndex="{Binding ViewModel.PagerInfo.CurrentPageIndex}"> <hc:Interaction.Triggers> <hc:EventTrigger EventName="PageUpdated"> <hc:EventToCommand Command="{Binding ViewModel.PageUpdatedCommand}" PassEventArgsToCommand="True" /> </hc:EventTrigger> </hc:Interaction.Triggers> </hc:Pagination> <TextBlock Margin="20,0,0,0" VerticalAlignment="Center" Text="共有记录数" /> <TextBlock Margin="10,0,0,0" VerticalAlignment="Center" Foreground="Blue" Text="{Binding ViewModel.MenuItems.Count}" /> <TextBlock Margin="10,0,0,0" VerticalAlignment="Center" Text="/" /> <TextBlock Margin="10,0,0,0" VerticalAlignment="Center" Foreground="Blue" Text="{Binding ViewModel.PagerInfo.RecordCount}" /> <TextBlock Margin="10,0,0,0" VerticalAlignment="Center" Text="条" /> </StackPanel>
而对于父级记录的处理,我们可以在里面增加一个下列树状列表的处理即可。
<DataGridTemplateColumn Width="150" Header="上级菜单"> <DataGridTemplateColumn.CellTemplate> <DataTemplate> <TextBlock Foreground="{Binding PID}" Text="{Binding PID, Converter={StaticResource MenuIdToNameConverter}}" /> </DataTemplate> </DataGridTemplateColumn.CellTemplate> <DataGridTemplateColumn.CellEditingTemplate> <DataTemplate> <control:MenuControl Text="" Value="{Binding PID, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> </DataTemplate> </DataGridTemplateColumn.CellEditingTemplate> </DataGridTemplateColumn>
这样就可以弹出下列列表的信息了,这样我们可以绑定各种不同的树状数据集合,从而达到更好的编辑处理体验了。
数据记录的删除操作,我们可以判断集合对象的Id是否为空,来判断是否是新增的,然后采用不同的方式删除处理。
/// <summary> /// 删除操作 /// </summary> /// <param name="info">业务对象</param> [RelayCommand] private async Task Delete(MenuInfo info) { if (info == null) return; if (info.Id.IsNullOrEmpty()) { this.ViewModel.MenuItems!.Remove(info); } else { if (MessageDxUtil.ShowYesNoAndWarning("您确认删除该记录?") != System.Windows.MessageBoxResult.Yes) return; this.ViewModel.DeleteCommand.Execute(info); } }
而保存的时候,我们对记录进行新增或者修改即可,统一处理。
/// <summary> /// 用于子类重写的保存更新操作 /// </summary> /// <returns></returns> protected virtual async Task<bool> InsertOrUpdate() { bool result = false; if (this.MenuItems != null) { foreach (var item in this.MenuItems) { await service.InsertOrUpdateAsync(item, item.Id); } result = true; } return result; }
以上就是我们在数据编辑的处理思路和常规的做法,如果您对界面有更高的要求,也可以和我一起讨论处理。
链接附注:
如对我们的代码生成工具有兴趣,可以到官网下载使用《代码生成工具Database2Sharp》。
如需了解我们官网对《SqlSugar开发框架》的介绍,可以参考《SqlSugar开发框架》了解。
如需阅读我们对于《SqlSugar开发框架》文章介绍,可以参考博客园的随笔标签《SqlSugar随笔 , WPF随笔》学习了解。
转载请注明出处:撰写人:伍华聪 http://www.iqidi.com