You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

WPF DataGrid无法对Protobuf Timestamp列排序的解决咨询

解决WPF DataGrid中Protobuf Timestamp列无法排序的问题

方案一:通过Sorting事件实现自定义排序

这是无需修改Protobuf类的快速方案,直接在UI层接管Timestamp列的排序逻辑:

  • 给DataGrid绑定Sorting事件:
    <DataGrid x:Name="YourDataGrid" Sorting="YourDataGrid_Sorting" AutoGenerateColumns="True"/>
    
  • 后台实现事件处理逻辑:
    private void YourDataGrid_Sorting(object sender, DataGridSortingEventArgs e)
    {
        if (e.Column.SortMemberPath != "Timestamp") return;
        
        // 阻止默认排序,避免触发报错
        e.Handled = true;
    
        var view = CollectionViewSource.GetDefaultView(YourDataGrid.ItemsSource) as ListCollectionView;
        if (view == null) return;
    
        // 设置自定义比较器,根据当前排序方向调整
        var sortDir = e.Column.SortDirection ?? ListSortDirection.Ascending;
        view.CustomSort = new TimestampComparer(sortDir);
    
        // 更新列的排序箭头显示
        e.Column.SortDirection = sortDir == ListSortDirection.Ascending 
            ? ListSortDirection.Descending 
            : ListSortDirection.Ascending;
    }
    
    // 自定义Timestamp比较器,利用Protobuf Timestamp自身的CompareTo方法
    private class TimestampComparer : IComparer
    {
        private readonly ListSortDirection _sortDir;
    
        public TimestampComparer(ListSortDirection sortDir) => _sortDir = sortDir;
    
        public int Compare(object x, object y)
        {
            var itemX = x as YourProtobufClass;
            var itemY = y as YourProtobufClass;
    
            if (itemX?.Timestamp == null && itemY?.Timestamp == null) return 0;
            if (itemX?.Timestamp == null) return _sortDir == ListSortDirection.Ascending ? -1 : 1;
            if (itemY?.Timestamp == null) return _sortDir == ListSortDirection.Ascending ? 1 : -1;
    
            var compareResult = itemX.Timestamp.CompareTo(itemY.Timestamp);
            return _sortDir == ListSortDirection.Descending ? -compareResult : compareResult;
        }
    }
    
    注意替换代码中的YourProtobufClass为你实际的自动生成类名。

方案二:转换Timestamp为.NET原生可排序类型(更简洁推荐)

Protobuf的Timestamp可以通过ToDateTimeOffset()方法转换为.NET原生的DateTimeOffset,该类型默认支持排序。你可以通过两种方式实现:

方式1:创建包装类

由于自动生成的Protobuf类无法修改,可创建包装类转发属性并转换Timestamp:

public class ProtobufItemWrapper
{
    public YourProtobufClass Original { get; set; }

    // 转发字符串属性示例
    public string StringProp1 => Original.StringProp1;
    public string StringProp2 => Original.StringProp2;

    // 转换Timestamp为可排序的DateTimeOffset
    public DateTimeOffset Timestamp => Original.Timestamp.ToDateTimeOffset();
}

将DataGrid的ItemsSource绑定到List<ProtobufItemWrapper>集合后,自动生成的Timestamp列会基于DateTimeOffset默认支持排序,无需额外处理。

方式2:利用AutoGeneratingColumn修改绑定

若不想创建包装类,可在列自动生成时转换绑定值:

<DataGrid x:Name="YourDataGrid" AutoGeneratingColumn="YourDataGrid_AutoGeneratingColumn" AutoGenerateColumns="True"/>

后台代码:

private void YourDataGrid_AutoGeneratingColumn(object sender, DataGridAutoGeneratingColumnEventArgs e)
{
    if (e.PropertyName == "Timestamp" && e.PropertyType == typeof(Google.Protobuf.WellKnownTypes.Timestamp))
    {
        var textColumn = e.Column as DataGridTextColumn;
        if (textColumn == null) return;

        // 替换绑定,加入转换器将Timestamp转为DateTimeOffset
        textColumn.Binding = new Binding("Timestamp")
        {
            Converter = new TimestampToDateTimeOffsetConverter()
        };
    }
}

// 转换器实现
public class TimestampToDateTimeOffsetConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value is Google.Protobuf.WellKnownTypes.Timestamp ts 
            ? ts.ToDateTimeOffset() 
            : DateTimeOffset.MinValue;
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

注意:这种方式下默认排序可能仍会调用原始Timestamp类型的比较逻辑,建议结合方案一的Sorting事件,或直接使用包装类方案更省心。

错误原因

Protobuf自动生成的Timestamp虽实现了IComparable<Timestamp>泛型接口,但WPF DataGrid的默认排序机制在反射获取比较器时,无法正确识别泛型接口的比较逻辑,导致抛出比较失败的异常。

内容的提问来源于stack exchange,提问作者Igor

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 02:17:11