DevExpress GridView日期列排序偶发崩溃问题求助
问题背景
使用DevExpress.XtraGrid.Views.Grid.GridView时,点击日期列(STUDY_DATE)表头排序会偶发导致应用程序崩溃。技术环境为C++/C#混合代码库+COM互操作,通过CustomUnboundColumnData事件实现自定义数据绑定。
列配置信息
- SortMode = ColumnSortMode.Custom
- 已注册
CustomColumnSort事件 - UnboundType = DevExpress.Data.UnboundColumnType.String
- DisplayFormat.FormatType = DateTime,FormatString = "dd\mm\yyyy hh:mm:ss"
CustomDrawCell中始终为RowCellCustomDrawEventArgs.DisplayText设置字符串值,CustomUnboundColumnData也返回该列的字符串值
崩溃分析
崩溃场景下所有行均为有效日期(无"Unknown"值),捕获到的异常为Object must be of type String。经分析,DevExpress在调用CustomColumnSort事件前会尝试用列的原始值执行内部比较,若原始值类型与UnboundType定义不一致,则会抛出异常引发崩溃。
解决方案
1. 严格保证值类型一致性
确保CustomUnboundColumnData事件中返回的值完全匹配UnboundType的定义(此处为String类型)。排查COM互操作数据传递环节,避免出现偶然返回DateTime或其他类型对象的情况,统一返回字符串格式的日期值。
2. 强制跳过默认比较逻辑
在CustomColumnSort事件实现中,务必设置e.Handled = true,并自行完成两行数据的比较逻辑。同时确认列的SortMode已严格设置为ColumnSortMode.Custom,这会告知DevExpress完全使用自定义排序逻辑,不再触发内部默认比较。
示例代码:
private void gridView_CustomColumnSort(object sender, DevExpress.XtraGrid.Views.Base.CustomColumnSortEventArgs e) { if (e.Column.FieldName == "STUDY_DATE") { // 从自定义数据源获取两行的日期字符串 string date1 = GetStudyDate(e.ListSourceRowIndex1); string date2 = GetStudyDate(e.ListSourceRowIndex2); // 转换为DateTime进行准确比较 DateTime dt1 = DateTime.Parse(date1); DateTime dt2 = DateTime.Parse(date2); e.Result = DateTime.Compare(dt1, dt2); e.Handled = true; // 强制使用自定义逻辑,跳过默认比较 } }
3. 修正UnboundType类型匹配
若业务逻辑中该列本质为日期类型,可将UnboundType改为DevExpress.Data.UnboundColumnType.DateTime,同时在CustomUnboundColumnData事件中返回DateTime对象而非字符串。DisplayFormat设置保持不变,既保证显示格式正确,又避免类型不匹配导致的内部比较异常。
4. 针对v12.2版本的临时规避
在触发排序操作前后,调用GridView的BeginDataUpdate()和EndDataUpdate()方法,锁定数据更新流程,减少内部刷新触发默认比较的概率:
private void gridView_ColumnHeaderClick(object sender, DevExpress.XtraGrid.Views.Grid.ColumnHeaderClickEventArgs e) { if (e.Column.FieldName == "STUDY_DATE") { gridView.BeginDataUpdate(); // 执行排序操作 gridView.EndDataUpdate(); } }
堆栈跟踪
N 7FFE990F5369 KERNELBASE!RaiseException+0x69 N 7FFE918210A8 clr!IEE+0x5dd8 N 7FFE91820D83 clr!IEE+0x5ab3 M 7FFE90CBE34F mscorlib!System.String.CompareTo(System.Object)+0 M 7FFE10FE5E3A DevExpress.Data.v12.2!DevExpress.Data.DataControllerBase.CompareRecords(DevExpress.Data.Helpers.DataColumnSortInfo[], Int32, Int32, Boolean)+213 M 7FFE10FF19F3 DevExpress.Data.v12.2!DevExpress.Data.VisibleListSourceRowCollection.QuickSort(DevExpress.Data.Helpers.DataColumnSortInfo[], Int32, Int32, Int32, Boolean)+74 M 7FFE10FF1A8A DevExpress.Data.v12.2!DevExpress.Data.VisibleListSourceRowCollection.QuickSort(DevExpress.Data.Helpers.DataColumnSortInfo[], Int32, Int32, Int32, Boolean)+154 M 7FFE10FF1A8A DevExpress.Data.v12.2!DevExpress.Data.VisibleListSourceRowCollection.QuickSort(DevExpress.Data.Helpers.DataColumnSortInfo[], Int32, Int32, Int32, Boolean)+154 M 7FFE10FF15FD DevExpress.Data.v12.2!DevExpress.Data.VisibleListSourceRowCollection.Sort(DevExpress.Data.Helpers.DataColumnSortInfoCollection)-1 M 7FFE10FE21DE DevExpress.Data.v12.2!DevExpress.Data.DataController.DoSortRows()-3 M 7FFE10FDF2E8 DevExpress.Data.v12.2!DevExpress.Data.DataController.OnRefresh(Boolean)+23 M 7FFE10FDF1B1 DevExpress.Data.v12.2!DevExpress.Data.DataController.DoRefreshCore(Boolean)+7 M 7FFE10FDF5F7 DevExpress.Data.v12.2!DevExpress.Data.DataController.DoRefresh(Boolean)+103 M 7FFE10FDF867 DevExpress.Data.v12.2!DevExpress.Data.DataController.DoSortGroupRefresh()+15 M 7FFE1B0BCD47 DevExpress.XtraGrid.v12.2!DevExpress.XtraGrid.Views.Base.ColumnView.EndDataUpdateCore(Boolean)+71 M 7FFE1B0BF19E DevExpress.XtraGrid.v12.2!DevExpress.XtraGrid.Views.Base.ColumnView.DoMouseSortColumn(DevExpress.XtraGrid.Columns.GridColumn, System.Windows.Forms.Keys)+124 M 7FFE1B0BF12E DevExpress.XtraGrid.v12.2!DevExpress.XtraGrid.Views.Base.ColumnView.DoMouseSortColumn(DevExpress.XtraGrid.Columns.GridColumn, System.Windows.Forms.Keys)-1 M 7FFE1B144B75 DevExpress.XtraGrid.v12.2!DevExpress.XtraGrid.Views.Grid.Handler.GridHandler.DoMouseSortColumn(DevExpress.XtraGrid.Columns.GridColumn, System.Windows.Forms.Keys)-3 M 7FFE1B1448F8 DevExpress.XtraGrid.v12.2!DevExpress.XtraGrid.Views.Grid.Handler.GridHandler.DoClickAction(DevExpress.XtraGrid.Views.Base.ViewInfo.BaseHitInfo)+156 M 7FFE1B1432F2 DevExpress.XtraGrid.v12.2!DevExpress.XtraGrid.Views.Grid.Handler.GridHandler.OnMouseUp(System.Windows.Forms.MouseEventArgs)+48 M 7FFE3AEF5258 DevExpress.Utils.v12.2!DevExpress.Utils.Controls.BaseHandler.ProcessEvent(DevExpress.Utils.Controls.EventType, System.Object)+218 M 7FFE1B098A59 DevExpress.XtraGrid.v12.2!DevExpress.XtraGrid.GridControl.OnMouseUp(System.Windows.Forms.MouseEventArgs)+116 M 7FFE8B4F196D System.Windows.Forms!System.Windows.Forms.Control.WmMouseUp(System.Windows.Forms.Message ByRef, System.Windows.Forms.MouseButtons, Int32)+388 M 7FFE8AD2196F System.Windows.Forms!System.Windows.Forms.Control.WndProc(System.Windows.Forms.Message ByRef)+1183 M 7FFE13F08149 DevExpress.XtraEditors.v12.2!DevExpress.XtraEditors.Container.EditorContainer.WndProc(System.Windows.Forms.Message ByRef)+103 M 7FFE1B0963BF DevExpress.XtraGrid.v12.2!DevExpress.XtraGrid.GridControl.WndProc(System.Windows.Forms.Message ByRef)+122 M 7FFE8B524E06 System.Windows.Forms!System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr, Int32, IntPtr, IntPtr)+37 M 7FFE8B4B0FE2 System.Windows.Forms!DomainBoundILStubClass.IL_STUB_ReversePInvoke(Int64, Int32, Int64, Int64)+0 N 7FFE9183009E clr!DllCanUnloadNowInternal+0x41ee N 7FFE99AEEF5C USER32!CallWindowProcW+0x60c N 7FFE99AEE684 USER32!DispatchMessageW+0x4a4 M 7FFE8ADAB609 System.Windows.Forms!DomainBoundILStubClass.IL_STUB_PInvoke(MSG ByRef)+0 M 7FFE8AD37361 System.Windows.Forms!System.Windows.Forms.Application+ComponentManager.System.Windows.Forms.UnsafeNativeMethods.IMsoComponentManager.FPushMessageLoop(IntPtr, Int32, Int32)+375 M 7FFE8AD36CC7 System.Windows.Forms!System.Windows.Forms.Application+ThreadContext.RunMessageLoopInner(Int32, System.Windows.Forms.ApplicationContext)+489 M 7FFE8AD36AC2 System.Windows.Forms!System.Windows.Forms.Application+ThreadContext.RunMessageLoop(Int32, System.Windows.Forms.ApplicationContext)+20 M 7FFE3F4253D3 SCN!SCN_ManagedApp.Run(SCN_ManagedApp*)+442 N 7FFE9183009E clr!DllCanUnloadNowInternal+0x41ee N 7FFE3E80C6C0 mfc140u+0x2ac6c0 N 1400314D6 mp!ATL::CComObjectRootExATL::CComMultiThreadModel::Unlock+0x22926 N 7FFE99CA7374 KERNEL32!BaseThreadInitThunk+0x14 N 7FFE9B85CC91 ntdll!RtlUserThreadStart+0x21
内容的提问来源于stack exchange,提问作者Loch

