循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(10) -- 在DataGrid上直接编辑保存数据

简介: 循序渐进介绍基于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随笔》学习了解。

 

专注于代码生成工具、.Net/.NetCore 框架架构及软件开发,以及各种Vue.js的前端技术应用。著有Winform开发框架/混合式开发框架、微信开发框架、Bootstrap开发框架、ABP开发框架、SqlSugar开发框架等框架产品。
 转载请注明出处:撰写人:伍华聪  http://www.iqidi.com
   

相关文章
|
3月前
|
C# 开发者 Windows
WPF 应用程序开发:一分钟入门
本文介绍 Windows Presentation Foundation (WPF),这是一种用于构建高质量、可缩放的 Windows 桌面应用程序的框架,支持 XAML 语言,方便 UI 设计与逻辑分离。文章涵盖 WPF 基础概念、代码示例,并深入探讨常见问题及解决方案,包括数据绑定、控件样式与模板、布局管理等方面,帮助开发者高效掌握 WPF 开发技巧。
173 65
|
4月前
|
C# UED 开发者
WPF与性能优化:掌握这些核心技巧,让你的应用从卡顿到丝滑,彻底告别延迟,实现响应速度质的飞跃——从布局到动画全面剖析与实例演示
【8月更文挑战第31天】本文通过对比优化前后的方法,详细探讨了提升WPF应用响应速度的策略。文章首先分析了常见的性能瓶颈,如复杂的XAML布局、耗时的事件处理、不当的数据绑定及繁重的动画效果。接着,通过具体示例展示了如何简化XAML结构、使用后台线程处理事件、调整数据绑定设置以及利用DirectX优化动画,从而有效提升应用性能。通过这些优化措施,WPF应用将更加流畅,用户体验也将得到显著改善。
301 1
|
4月前
|
容器 C# Docker
WPF与容器技术的碰撞:手把手教你Docker化WPF应用,实现跨环境一致性的开发与部署
【8月更文挑战第31天】容器技术简化了软件开发、测试和部署流程,尤其对Windows Presentation Foundation(WPF)应用程序而言,利用Docker能显著提升其可移植性和可维护性。本文通过具体示例代码,详细介绍了如何将WPF应用Docker化的过程,包括创建Dockerfile及构建和运行Docker镜像的步骤。借助容器技术,WPF应用能在任何支持Docker的环境下一致运行,极大地提升了开发效率和部署灵活性。
151 1
|
4月前
|
安全 C# 数据安全/隐私保护
WPF安全加固全攻略:从数据绑定到网络通信,多维度防范让你的应用固若金汤,抵御各类攻击
【8月更文挑战第31天】安全性是WPF应用程序开发中不可或缺的一部分。本文从技术角度探讨了WPF应用面临的多种安全威胁及防护措施。通过严格验证绑定数据、限制资源加载来源、实施基于角色的权限管理和使用加密技术保障网络通信安全,可有效提升应用安全性,增强用户信任。例如,使用HTML编码防止XSS攻击、检查资源签名确保其可信度、定义安全策略限制文件访问权限,以及采用HTTPS和加密算法保护数据传输。这些措施有助于全面保障WPF应用的安全性。
62 0
|
4月前
|
C# 开发者 Windows
全面指南:WPF无障碍设计从入门到精通——让每一个用户都能无障碍地享受你的应用,从自动化属性到焦点导航的最佳实践
【8月更文挑战第31天】为了确保Windows Presentation Foundation (WPF) 应用程序对所有用户都具备无障碍性,开发者需关注无障碍设计原则。这不仅是法律要求,更是社会责任,旨在让技术更人性化,惠及包括视障、听障及行动受限等用户群体。
95 0
|
4月前
|
测试技术 C# 开发者
“代码守护者:详解WPF开发中的单元测试策略与实践——从选择测试框架到编写模拟对象,全方位保障你的应用程序质量”
【8月更文挑战第31天】单元测试是确保软件质量的关键实践,尤其在复杂的WPF应用中更为重要。通过为每个小模块编写独立测试用例,可以验证代码的功能正确性并在早期发现错误。本文将介绍如何在WPF项目中引入单元测试,并通过具体示例演示其实施过程。首先选择合适的测试框架如NUnit或xUnit.net,并利用Moq模拟框架隔离外部依赖。接着,通过一个简单的WPF应用程序示例,展示如何模拟`IUserRepository`接口并验证`MainViewModel`加载用户数据的正确性。这有助于确保代码质量和未来的重构与扩展。
109 0
|
4月前
|
前端开发 C# 设计模式
“深度剖析WPF开发中的设计模式应用:以MVVM为核心,手把手教你重构代码结构,实现软件工程的最佳实践与高效协作”
【8月更文挑战第31天】设计模式是在软件工程中解决常见问题的成熟方案。在WPF开发中,合理应用如MVC、MVVM及工厂模式等能显著提升代码质量和可维护性。本文通过具体案例,详细解析了这些模式的实际应用,特别是MVVM模式如何通过分离UI逻辑与业务逻辑,实现视图与模型的松耦合,从而优化代码结构并提高开发效率。通过示例代码展示了从模型定义、视图模型管理到视图展示的全过程,帮助读者更好地理解并应用这些模式。
118 0
|
4月前
|
存储 C# 关系型数据库
“云端融合:WPF应用无缝对接Azure与AWS——从Blob存储到RDS数据库,全面解析跨平台云服务集成的最佳实践”
【8月更文挑战第31天】本文探讨了如何将Windows Presentation Foundation(WPF)应用与Microsoft Azure和Amazon Web Services(AWS)两大主流云平台无缝集成。通过具体示例代码展示了如何利用Azure Blob Storage存储非结构化数据、Azure Cosmos DB进行分布式数据库操作;同时介绍了如何借助Amazon S3实现大规模数据存储及通过Amazon RDS简化数据库管理。这不仅提升了WPF应用的可扩展性和可用性,还降低了基础设施成本。
95 0
|
7月前
|
C# 开发者 Windows
基于Material Design风格开源、易用、强大的WPF UI控件库
基于Material Design风格开源、易用、强大的WPF UI控件库
398 0
|
4月前
|
开发框架 缓存 前端开发
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件
循序渐进介绍基于CommunityToolkit.Mvvm 和HandyControl的WPF应用端开发(11) -- 下拉列表的数据绑定以及自定义系统字典列表控件