WPF DataGrid 如何将被选中行带到视野中


WPF DataGrid 如何将被选中行带到视野中

魏刘宏 2021 年 12 月 11 日

前言

在 WPF 开发中,显示表格一般使用 DataGrid 控件,而且我们一般会依据用户的选中行的操作来执行一些逻辑,这种情况,选中了哪一行,用户是心知肚明的。而还有一种情况,我们可能在业务逻辑中,由程序自己选中了某一行,如果这一行当前不在用户界面的可视区(换句话说也就是滚动条没有滚到那个位置),那么我们如何将其带到用户的视野中呢?

 

准备工作

今天准备介绍两个方法。正所谓,工欲善其事必先利其器,所以在开始之前,我们先来构建一个可以模拟后台选中行的功能。

使用的还是之前用过的 DataGrid 的 Demo 程序(在《WPF DataGrid 通过自定义表头模拟首行固定》和《WPF 触屏事件后触发鼠标事件的问题及 DataGrid 误触问题》中用过),加了一个可以填写要选中的行号的文本框,以及一个执行选中操作的按钮:

WPF DataGrid 如何将被选中行带到视野中插图

 

下面来演示一下没有自动将选中行带到视野中的情况。我们先将数据添加到 10 条,然后缩小程序的窗口,这样有些数据就在滚动区外面了,也就是不在视野中。然后我们通过程序来选中行,可以看到选中功能是正常的,但是对于视野外的数据,用户看不到其是否选中,需要手动滚动来寻找,如下图(动图):

WPF DataGrid 如何将被选中行带到视野中插图1

 

好,那接下来就介绍怎么解决吧。

 

方法一

这个方法是参考《【翻译】WPF 中附加行为的介绍 Introduction to Attached Behaviors in WPF》文章中的将 TreeViewItem(树状列表项)带到视野中的方法,我稍微改造了一下,使其同时支持 DataGridRow 和 TreeViewItem,并且之后如果有其它受支持的类型也可以方便地扩展。BringIntoViewBehavior 类提供了一个 IsBroughtIntoViewWhenSelected 附加属性,给每个列表项的 Selected 事件指定了处理方法,处理方法中调用 BringIntoView () 方法,完整代码如下:

 
using System.Windows;
using System.Windows.Controls;
/*
 * 源码已托管:https://gitee.com/dlgcy/WPFTemplateLib
 */
namespace WPFTemplateLib.WpfHelpers
{
    /// <summary>
    /// 功能:列表项被选中时带到视野中
    /// 参考:http://dlgcy.com/introduction-to-attached-behaviors-in-wpf/
    /// 说明:用于 DataGrid 时需要设置 EnableRowVirtualization="False"
    /// </summary>
    /// <example>
    /// <code>
    /// Setter Property="wpfHelpers:BringIntoViewBehavior.IsBroughtIntoViewWhenSelected" Value="True"/>
    /// </code>
    /// </example>
    public class BringIntoViewBehavior
    {
        #region IsBroughtIntoViewWhenSelected
        public static bool GetIsBroughtIntoViewWhenSelected(FrameworkElement item)
        {
            return (bool)item.GetValue(IsBroughtIntoViewWhenSelectedProperty);
        }
        public static void SetIsBroughtIntoViewWhenSelected(FrameworkElement item, bool value)
        {
            item.SetValue(IsBroughtIntoViewWhenSelectedProperty, value);
        }

        /// <summary>
        /// 是否在选中时带到视野中
        /// </summary>
        public static readonly DependencyProperty IsBroughtIntoViewWhenSelectedProperty =
            DependencyProperty.RegisterAttached(
                "IsBroughtIntoViewWhenSelected",
                typeof(bool),
                typeof(BringIntoViewBehavior),
                new UIPropertyMetadata(false, OnIsBroughtIntoViewWhenSelectedChanged));

        static void OnIsBroughtIntoViewWhenSelectedChanged(DependencyObject depObj, DependencyPropertyChangedEventArgs e)
        {
            FrameworkElement item = depObj as FrameworkElement;

            if (item == null)
                return;

            if (e.NewValue is bool == false)
                return;

            switch (depObj)
            {
                case DataGridRow row:
                {
                    if ((bool)e.NewValue)
                        row.Selected += OnItemSelected;
                    else
                        row.Selected -= OnItemSelected;
                    break;
                }
                case TreeViewItem treeViewItem:
                {
                    if ((bool)e.NewValue)
                        treeViewItem.Selected += OnItemSelected;
                    else
                        treeViewItem.Selected -= OnItemSelected;
                    break;
                }
                default:
                    break;
            }
        }

        static void OnItemSelected(object sender, RoutedEventArgs e)
        {
            //忽略所有只是报告子孙的 Selected 被触发的祖先。
            if (!ReferenceEquals(sender, e.OriginalSource))
                return;

            if (e.OriginalSource is FrameworkElement item)
                item.BringIntoView();
        }

        #endregion
    }
}

 

此方法用于 DataGrid 时需要设置 EnableRowVirtualization="False"(默认为 true):

WPF DataGrid 如何将被选中行带到视野中插图2

WPF DataGrid 如何将被选中行带到视野中插图3

 

使用时只要在行样式中应用这个附加属性即可:

WPF DataGrid 如何将被选中行带到视野中插图4

 

注意引入命名空间:

WPF DataGrid 如何将被选中行带到视野中插图5

 

效果如下(动图):

WPF DataGrid 如何将被选中行带到视野中插图6

 

方法二

如果开了行虚拟化(EnableRowVirtualization="True"),离可视区较远的行的 Selected 事件就不会被触发,以上方法就不行了。

类似于这个帖子的情况《WPF 开启行虚拟化的时候,行选择功能不正常,求解决方案》(https://bbs.csdn.net/topics/392666509):

WPF DataGrid 如何将被选中行带到视野中插图7

 

所以如果因为数据量比较大必须开启行虚拟化时,可以使用下面的方法。

先给 DataGrid 命个名(如 x:Name="Dg" )方便后台使用,然后在 ViewModel 中添加一个选中项改变事件 SelectedItemChanged,并在选中项改变时调用(参数为选中行的索引):

/// <summary>
/// 选中项改变事件
/// </summary>
public event Action<int> SelectedItemChanged;

private User _SelectedItem;
/// <summary>
/// 选中项
/// </summary>
public User SelectedItem
{
    get => _SelectedItem;
    set
    {
        SetProperty(ref _SelectedItem, value);

        SelectedItemChanged?.Invoke(Datas.IndexOf(_SelectedItem));
    }
}

 

接着在后台事件中注册事件处理方法,处理方法中调用了 DataGrid 的 ScrollIntoView 方法,代码如下:

_vm.SelectedItemChanged += OnSelectedItemChanged;

/// <summary>
/// 选中项改变事件执行方法
/// </summary>
/// <param name="index">选中行索引</param>
private void OnSelectedItemChanged(int index)
{
    Dg.ScrollIntoView(Dg.Items.GetItemAt(index));
}

 

效果和方法一的一样,就不再赘述了。

 

总结

关于将 DataGrid 选中行带到视野中的需求,本文介绍了两种方法。方法一提供了一个附加属性,可以方便地实现该需求,不过要求不能开启行虚拟化。方法二则是需要在 ViewModel 和页面后台编写代码,通过事件来触发相关操作,不过可以支持行虚拟化。大家可以依据实际情况选择使用,如果有更好的方法,欢迎交流。

 

源代码地址:https://gitee.com/dlgcy/DLGCY_WPFPractice/tree/Blog20211211 

 

 
文章来源:https://www.cnblogs.com/weiliuhong/p/wpf-datagrid-bring-selected-row-into-view.html

版权声明:本文为YES开发框架网发布内容,转载请附上原文出处连接
管理员
上一篇:.Net 下高性能分表分库组件-连接模式原理
下一篇:在Winform框架的多文档界面中实现双击子窗口单独弹出或拖出及拽回的处理
评论列表

发表评论

评论内容
昵称:
验证码:
验证码
关联文章

WPF DataGrid 如何中行视野
如何命令添加VisualStudio控制台?
selenium爬虫检测如何
WPF Command绑定并传参(以DataGrid示例)
Devexpress GridView焦点离开表格的时候保持中行的选中颜色
Python Selenium 爬虫如何隐藏Headles-Chrome不检测出来 避免检测
WPF开发随笔收录-递增递减按钮TextBox
在 SA 和 Windows 等账户都禁用的情况下如何登录?
Python Selenium 前端如何检测Chrome-Headless不爬虫虐
日期条件的BAQ
WPF对象级资源
WPF程序级资源
如何在 Entity Framework 自动截断超长字符串并避免异常
走进WPF之MVVM完整案例
Http请求Referer的设置,CEFSharpReferer请求
数据库发生这个错误:无法为数据库 的对象 分配空间,因为 'PRIMARY' 文件组已满。请删除不需要的文件、删除文件组的对象、其他文件添加文件组或为文件组的现有文件启用自动增长,以便增加可用磁盘空间。
[WPF] 用 Effect 实现线条光影效果
WPF_15_格式化绑定的数据
如何在 Vue 2 使用 Webpack 构建时为 favicon.ico 设置自定义根路径前缀
[WPF] 实现 WPF 的 Inner Shadow

热门标签
.NET Core .NET Reactor ag-grid AI发布 api安全 ASP.NET Core C#DLL加密 C#播放声音 C#代码混淆 C#代码加密 ChromeDriver Codex DateTime DBeaver devexpress devTool DLL混淆 edge.js EF EFCore Electron element-ui el-form el-table excel FastReport FileStream FolderBrowerDialog FolderSelectDialog form提交 git gridcontrol gridview input javascript json字符串 JS转换对象JSON jwt JWT授权 linq log Math MCP mitmproxy MVC MySQL Navicat netstat nginx node_modules NSwag Nuget Nuget镜像 number PowerShell pyinstaller python pythoncom python爬虫 python抓包 pywin32 redis Requests-html RestSharp Selenium sql SQL Server Swagger to-cms Visual Studio VSCode vue VueRouter vue路由 VUE页面通讯 Webpack Windows Windows服务 winform wmi xlrd yaml YESCMS YESWEB开发框架 白象 表单提交 播放声音 打开URL 代码混淆 弹窗提醒 端口占用 对象转换 分布式 公共字典 机器码 进程排查 静态资源 开发指南 路由参数 密钥 配置教程 配置文件 权限 人工智能 任务 任务调度 日期间隔 日志 日志记录 省市区 授权验证 数据库 四舍五入 文案 文件读取 文件夹选择 文件目录选择 问题排查 行政区域数据 页面通讯 中间件 CSharp 事务锁 工单系统 并发控制 重复提交 CMS Markdig Markdown markdown-it marked 技术选型 VS Code 开发工具 源代码管理 版本控制 Docker PostgreSQL 时区 部署排查 CMS架构 EF Core 主题系统 二次开发 插件系统 容器 运维命令 镜像清理 Linux NAS 远程挂载 飞牛 fnOS S/4HANA SAP GUI SAP HANA SAP R/3 SAP入门 SAP版本 ERP SAP SAP MM 库存管理 物料管理 采购管理 入门教程 SAP S/4HANA SPRO 企业结构 采购组织 MM01 物料主数据 物料类型 BP分组 业务伙伴 供应商主数据 ME41 RFQ 库存物料 采购流程 ME51 消耗性物料 科目分配 采购申请 AC03 ML81N 外部服务 服务主数据 Business Partner SAP培训 ME51N MM模块 Lean Services MM-SRV 外部服务采购 PIR 供应来源 采购主数据 采购信息记录 ME31K 框架协议 计划协议 采购合同 ME01 供应来源确定 货源清单 MEQ1 供应源确定 配额安排 配额评分 MD04 MD21 MRP 计划文件 需求计划 批量程序 MD01N MD02 MRP Live MD05 MM 物料计划 优化采购 供应源 采购订单 ME2A 供应商确认 采购监控 Flexible Workflow 凭证释放 采购审批 释放策略 实地盘点 物料凭证 货物移动 MIGO 收货 移动类型 已撤回 供应商退货 货物发出 STO 库存转储 转移过账 生产订单 预留 GR/IR MIRO 供应商发票 物流发票校验 OMR2 税码 FI PP SD 实操教程 MRBR OMR6 发票差异 交货成本 后续借记 MI01 实物盘点 盘点差异 公司代码 工厂 组织结构 OMS2 主数据定制 自动科目确定 BP角色 CVI 伙伴确定 编号范围 凭证类型 字段选择 FBN1 OMBT OMC2 会计凭证 OMJJ BOM 委外加工 项目类别L MRKO 供应商寄售 特殊库存K MRKON PIPE Pipeline 特殊库存P ERS MRIS 发票计划 周期性结算 里程碑付款 变更追踪 版本管理 采购凭证 SFTP WebDAV 网盘 飞牛fnOS AMPL HERS MPN 中文教程 库存确定 可用性检查 缺件检查 Output Management 消息确定 输出确定 分割评估 库存计价 评估类别 评估类型 PB00 RM0000 条件技术 采购定价 MM-FI集成 OBYC 库存估价 文本类型 文本采用 EFB EVO MSV SU3 用户参数 发票校验 合同参照 履约保留款 特别总账 预付款 Fiori Launchpad SAP Fiori 应用导航 用户体验 LSMW LTMC Migration Cockpit 数据迁移 BRFplus OPD Output Control My Inbox 审批流程 灵活工作流 SAP PP 外部加工 SAP QM 检验批 质量信息记录 采购收货 SAP PM 维护BOM 维护订单 SAP SD SAP Service 端到端流程 MM模块培训 FI-MM集成 供应商管理 审批配置 FICO入门 SAP FICO 财务配置 供应商税务 预扣税 House Bank 银行对账 客户清账 应收账款 FI控制 验证与替代 印度 GST 税务配置 F110 FBZP EWM入门 SAP EWM 仓库管理 OX14 成本核算 物料评估 后勤配置 物料组 价值更新 数量更新 PP-PI 流程制造 生产计划 容差配置 SAP事务码 SAP基础 TCODE Basis 事务代码 MMNR 编号区间 采购实操 组织架构 OMSF SAP实操 FI配置
联系我们
联系电话:15090125178(微信同号)
电子邮箱:garson_zhang@163.com
站长微信二维码
微信二维码