【问题标题】:How to sort all but first column in WPF DataGrid如何对WPF DataGrid中除第一列之外的所有列进行排序
【发布时间】:2012-04-25 17:49:19
【问题描述】:

我有一个 WPF DataGrid,它的第一列包含一个数字,即“排名”或“位置”。我想要的是,当我单击一列以根据该列对表格进行排序时,第一列保持原样。

例如:

职位名称 比赛积分 PPG 1约翰2 10 5 2 玛丽 3 12 4

当按游戏降序排序时应该变成

职位名称 比赛积分 PPG 1 玛丽 3 12 4 2约翰2 10 5

有没有办法做到这一点? DataColumn 似乎没有任何此类属性,并且 FreezeColumnsCount 仅始终将它们保留在视图中,但不会阻止它们与其余数据一起排序。

【问题讨论】:

  • 如果您从数据库中获取数据,您可以使用 sql 按子句的 order by 对其进行排序,除非您使用 datagridview,此功能是内置的,无需任何代码。
  • @justin-kirk 我正在使用数据库,但我不想一直执行 SQL 请求,因为该功能位于可单击的列标题中。而且我没有使用 DataGridView,而是 WPF DataGrid。您仍然确定该功能是内置的吗?即使在排序之后,如何保持第一列不变?
  • 该功能存在,.... 但是如果您是 xaml 的初学者,我强烈建议您使用 sql。写出一个体面的解决方案给我一秒钟
  • 我会使用 DataGridRowHeader 而不是 DataGridColumn 来显示位置。
  • 用户是否需要编辑单元格?

标签: c# wpf datagrid


【解决方案1】:

http://social.msdn.microsoft.com/Forums/en-US/wpf/thread/ffd7037d-dd77-44ec-9011-d0d43d5706aa/ 中,我刚刚找到了我在评论中建议的示例(来自 Adbie 的回答):

<DataGrid LoadingRow="dg_LoadingRow">
    <DataGrid.RowHeaderTemplate>
        <DataTemplate>
            <TextBlock Text="{Binding Path=Header, RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" />
        </DataTemplate>
    </DataGrid.RowHeaderTemplate>
</DataGrid>


private void dg_LoadingRow(object sender, DataGridRowEventArgs e)
{
    e.Row.Header = (e.Row.GetIndex() + 1).ToString();
}


由 OP 编辑​​:
我刚刚验证了它即使没有绑定也能正常工作。 cs代码很好,但在XAML中你只需要这样做

<DataGrid LoadingRow="dg_LoadingRow" />

【讨论】:

  • 这看起来比我的解决方案简单得多。绑定真的有必要吗?看来您正在绑定 RowHeaderTemplate 以显示行标题。这似乎是多余的。默认的 RowHeaderTemplate 是什么样的?
  • 目前我不在,无法自己测试。也许还有进一步改进的空间。
  • 谢谢。简单多了。又一个教训,又一个问题解决了!我已经编辑了答案以表明不需要绑定,就像@cadrell0 猜测的那样。如果需要,请随时将编辑合并到您的答案中。
  • @cadrell0 哇,比我想象的还要简单。感谢您的合作,现在它确实是一个巧妙的解决方案。
【解决方案2】:

我会为此使用ValueConverter。我不能确切地告诉你怎么做,但是,你要查看的是 DataGrid 上的属性ItemContainerGenerator

DataGrid 属性添加到您的ValueConverter,以便您可以从Convert 方法访问该属性。现在,在转换中,您需要调用 ContainerFromItem 来获取 UI 对象,然后调用 IndexFromContainer 来获取行的索引。我相信你会遇到一些问题,但这应该让你开始。

这样做的好处是您不必自己进行排序。这将依赖于 SortDescriptions 添加到 DataGrid 使用的 ICollectionView(如果您不绑定到一个,它会自动为您创建)。

编辑

这是请求的代码示例。我自己不需要这样做,但这是我要开始的地方。

这是转换后的建议值的外观

public ItemPositionValueConverter : IValueConverter
{
    public DataGrid DataGrid { get; set; }

    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        if (value == null)
        {
            return null;
        }

        if (DataGrid == null)
        {
            return null;
        }

        ItemContainerGenerator generator = DataGrid.ItemContainerGenerator;
        return generator.IndexFromContainer(generator.ContainerFromItem(value));
    }

    //you probably don't need ConvertBack put it is provided for completeness
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        int? index = value as int?

        if (index == null)
        {
            return null
        }

        if (DataGrid == null)
        {
            return null;
        }

        ItemContainerGenerator generator = DataGrid.ItemContainerGenerator;
        return generator.ItemFromContainer(generator.ContainerFromIndex(index.Value));
    }
}

现在用这个做一些类似的事情。

<UserControl>
    <UserControl.Resources>
        <ItemPositionValueConverter x:Key=ItemPositionValueConverter"
                                    DataGrid="{Binding ElementName=MyDataGrid}" />
    </UserControl.Resources>

    <DataGrid x:Name="MyDataGrid" ItemsSource="{Binding ....}">
        <DataGrid.Columns> 
            <DataGridTextColumn Header="Position"
                                Binding="{Binding Converter={StaticResource ItemPositionValueConverter}}"/>
        </DataGrid.Columns>
</UserControl>

注意,使用此解决方案,无需手动将排序添加到 ICollectionView。单击列标题时,将自动应用排序。

**免责声明:此代码已经过测试,可能与描述的功能不完全相同。这里是提供者来演示所需的逻辑。因此,它可能包含拼写错误或错误。任何尝试使用此代码的人都应该执行自己的测试以验证它是否适合他们的需求。

【讨论】:

  • 提供某种代码示例?您向尚不知道该问题答案的人提供的内容太不清楚:请阅读meta.stackexchange.com/questions/7656/…,请注意这不是巨魔尝试;我也很感兴趣,因为我将上面的代码用作排序机制,并且由于它“未参数化”,我很好奇如何改进它。
  • 投了赞成票;如果我不能让它工作,我可能会在我测试它时取消投票 (>^_^)>
  • 令我惊讶的是,没有更简单的方法可以让列在排序期间保持原样。如果我要真正理解其中的任何内容,我将不得不做很多阅读。感谢您抽出宝贵时间回答,@cadrell0。
【解决方案3】:

新答案:

所以我的最后一个答案显然不符合标准,我做了一些研究,看起来你可以像这样做你想要的:

 Dim view As ICollectionView = CollectionViewSource.GetDefaultView(ListViewName.Items)
 view.SortDescriptions.Add(New SortDescription("Field To Sort By", 0))

在哪里

  • “排序依据的字段”是列名称
  • # 是方向,0 为升序,1 为降序

注意:

  • 您必须在更改列表中同一列的排序顺序之间调用 view.SortDescriptions.Clear()

【讨论】:

  • 排序是简单的部分。真正的挑战是获取在排序更改时不会更改的行号。
  • 是的,这就是问题的重点。我熟悉排序数据。我知道如何在 SQL 中执行此操作,并且我知道如何正确设置列类型以便 DataGrid 正确排序。 LPL回答了我的问题。感谢您抽出宝贵时间回答。
猜你喜欢
  • 2021-09-24
  • 2013-12-31
  • 1970-01-01
  • 1970-01-01
  • 2010-12-11
  • 2012-11-04
  • 2017-10-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多