Telerik RadGridView横向滚动时GridViewComboBoxColumn选择变更事件误触发
问题根因
RadGridView默认开启UI虚拟化,横向滚动时移出可视区域的单元格会被回收复用,进入可视区域的单元格会重新构建可视化树。你通过AddHandler全局注册了所有子元素的RadComboBox.SelectionChangedEvent,GridViewComboBoxColumn生成的下拉框在重建、绑定数据的过程中会自动触发SelectionChanged事件,这类事件并非用户手动修改选择导致,属于控件加载过程中的正常触发。
解决方案
方案1:事件过滤(改动最小,无需调整现有绑定逻辑)
直接在OnSelectionChanged方法开头加两层校验,过滤掉非用户操作、非编辑状态下触发的无效事件:
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e) { // 过滤非RadComboBox触发的事件 if (e.OriginalSource is not RadComboBox comboBox) return; // 过滤无焦点、下拉未打开状态下程序化触发的事件 if (!comboBox.IsKeyboardFocusWithin && !comboBox.IsDropDownOpen) { e.Handled = true; return; } // 过滤非编辑状态单元格触发的事件(滚动重绘的单元格默认不在编辑态) var parentCell = comboBox.ParentOfType<GridViewCell>(); if (parentCell == null || !parentCell.IsInEditMode) { e.Handled = true; return; } // 此处保留原有业务逻辑 }
说明:ParentOfType是Telerik内置的可视化树查找扩展方法,可直接调用无需额外引入依赖。
方案2:使用GridView原生编辑事件(规范性最高,从根源避免无效触发)
全局监听内部子元素的路由事件本身就容易混入控件生命周期触发的无效事件,直接使用RadGridView自带的CellEditEnded事件处理下拉选择变更即可,该事件仅在用户确认完成单元格编辑时触发,完全不受滚动、虚拟化重绘影响:
- 删除构造函数中原有
AddHandler注册SelectionChanged事件的代码 - 给RadGridView控件添加事件绑定:
<telerik:RadGridView x:Name="rgvMEO" MinWidth="1000" HorizontalAlignment="Stretch" VerticalAlignment="Stretch" controls:ChildViewService.IsMainRadGridViewElement="True" IsFilteringAllowed="True" IsReadOnly="False" ItemsSource="{Binding MonthEndOverrideList, Mode=TwoWay}" SelectionMode="Extended" ShowColumnFooters="True" CellEditEnded="rgvMEO_CellEditEnded"> - 后台编写事件处理逻辑,仅处理目标列的提交操作:
private void rgvMEO_CellEditEnded(object sender, GridViewCellEditEndedEventArgs e) { // 仅处理主审核人列的提交编辑事件 if (e.Cell.Column.UniqueName != "colPR" || e.EditAction != GridViewEditAction.Commit) return; // 读取用户选中的新值,执行业务逻辑 var selectedReviewer = e.NewValue; }
方案3:关闭对应列的虚拟化(兜底方案,简单粗暴)
如果前两种方案不适用,可直接关闭目标ComboBox列的虚拟化,滚动时不会销毁重建对应单元格,从源头避免重绘触发的SelectionChanged事件。该方案仅在数据量较大时会轻微影响加载性能,千条以内数据无感知:
给colPrimaryReviewer列添加IsVirtualized="False"配置即可:
<telerik:GridViewComboBoxColumn x:Name="colPrimaryReviewer" Header="Primary Reviewer" HeaderTextAlignment="Center" IsFilterable="True" EditTriggers="CellClick" ItemsSource="{Binding PrimaryReviewerList, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=UserControl}}" DataMemberBinding="{Binding PrimaryReviewerDisplayName, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" DisplayMemberPath="DisplayName" UniqueName="colPR" IsReadOnly="False" CellStyle="{StaticResource GridViewCellStylePR}" IsVirtualized="False" />
内容的提问来源于stack exchange,提问作者Gurdeep
相关产品推荐
相关产品推荐

