在WPF DataGrid上显示行号的简单方法

34

我只想在我的DataGrid的最左列显示行号,是否有相应的属性可以实现这个功能?

请注意,这不是我的表的主键。当列排序时,我不希望这些行号随着它们所在的行移动。我基本上只想要一个连续的计数器。甚至不需要表头。


可能是如何为WPF工具包数据网格显示行索引?的重复问题。 - Dan J
1
也许我误解了问题,您是想为此单独创建一列,还是行标题也可以? - Fredrik Hedblad
1
“RowHeader” 很完美,谢谢。 - JohnB
如果您正在使用MSSQL Server 2005+,您可以尝试:http://msdn.microsoft.com/en-us/library/ms186734.aspx - nvcnvn
8个回答

53

一种方法是在DataGrid的LoadingRow事件中添加它们。

<DataGrid Name="DataGrid" LoadingRow="DataGrid_LoadingRow" ...

void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
    e.Row.Header = (e.Row.GetIndex()).ToString(); 
}

当从源列表添加或删除项目时,数字可能会在一段时间内失去同步。为了解决此问题,请参见以下链接:
WPF 4 DataGrid:将行号放入行标题中

可以像这样使用

<DataGrid ItemsSource="{Binding ...}"
          behaviors:DataGridBehavior.DisplayRowNumber="True"> 

这会在排序期间移动行号吗?还是LoadingRow也会在排序期间调用,从而使行号始终保持有序? - VoodooChild
2
@VoodooChild:是的,我已经用过几次了,就我所知,即使进行排序、滚动、更改ItemsSource等操作,行号始终按正确顺序排列。尽管有人告诉我这对他不起作用,但我要求他提供更多信息,但他从未回复。但对于我来说,我从未见过这种情况失败的情况 :) - Fredrik Hedblad
3
如果你想从#1开始:e.Row.Header = (e.Row.GetIndex() + 1).ToString(); 翻译为: 如果您想从#1开始:e.Row.Header = (e.Row.GetIndex() + 1).ToString(); - JohnB
确保属性HeadersVisibility设置为AllRowColumnsNone将不会显示。例如: <DataGrid HeaderVisibility="All"></DataGrid> - p__d
1
这在虚拟化中不起作用。 如何调整代码以使其与虚拟行一起工作? - JobaDiniz

15

添加关于Fredrik Hedblad答案的简短信息。

<DataGrid Name="DataGrid" LoadingRow="DataGrid_LoadingRow" ...

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

...如果您想从1开始编号


13
如果您的数据网格的ItemsSource绑定到一个集合,那么将您的数据网格的AlternationCount属性绑定到集合的count属性或者DataGrid的Items.Count属性。
<DataGrid ItemsSource="{Binding MyObservableCollection}" AlternationCount="{Binding MyObservableCollection.Count}" />

或者:

<DataGrid ItemsSource="{Binding MyObservableCollection}" AlternationCount="{Binding Items.Count, RelativeSource={RelativeSource Self}" />

要么都可以。
然后,假设您在最左边的列使用了DataGridTextColumn,在DataGrid.Columns定义中执行以下操作:
<DataGrid.Columns>
   <DataGridTextColumn Binding="{Binding AlternationIndex, RelativeSource={RelativeSource AncestorType=DataGridRow}}" />
</DataGrid.Columns>

如果你不想从0开始,你可以在绑定中添加一个转换器来增加索引。

2
如果您在数据网格中滚动并重新加载集合,则此方法将无法正常工作。编号将从数据网格中滚动到的顶部项目开始从0开始计数。 - Jesper
1
这对我有用,但是当我使用鼠标滚动数据网格时,索引号会随机更改。如何解决这个问题? - Dharti Sojitra

6

这个问题比较老,但我想分享一些东西。我遇到了类似的问题,所需要的只是行头数字的简单枚举 RowHeader ,而Fredrik Hedblad的答案几乎已经解决了我的问题。

虽然这很好:

<DataGrid Name="DataGrid" LoadingRow="DataGrid_LoadingRow" ...

void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
    e.Row.Header = (e.Row.GetIndex()).ToString(); 
}

当删除和添加项目时,我的标题出现了问题。如果你有负责此操作的按钮,只需在“删除”代码下添加dataGrid.Items.Refresh();,就像在我的情况下一样:

private void removeButton_Click(object sender, RoutedEventArgs e)
{
    // delete items

    dataGrid.Items.Refresh();
}

这对我解决了不同步的编号问题,因为刷新项会再次调用DataGrig_LoadingRow


4

补充一下关于这个问题的讨论...(我花了太多时间来找到这个答案!)

要避免行排序错误,您需要将数据网格的EnableRowVirtualization设置为False:

EnableRowVirtualization="False"

默认情况下,EnableRowVirtualization 属性被设置为 true。当 EnableRowVirtualization 属性被设置为 true 时,DataGrid 不会为绑定数据源中的每个数据项实例化一个 DataGridRow 对象。相反,DataGrid 仅在需要时创建 DataGridRow 对象,并尽可能重复使用它们。MSDN 参考文档

2
禁用虚拟化是不好的...有没有办法让它与虚拟化一起工作? - JobaDiniz

2
在对NGI修复和扩展的示例进行了一些RowHeaderStyle测试后,最初的回答如下:

        <DataGrid EnableRowVirtualization="false" ItemsSource="{Binding ResultView}" AlternationCount="{Binding ResultView.Count}" RowHeaderWidth="10">
            <DataGrid.RowHeaderStyle>
                <Style TargetType="{x:Type DataGridRowHeader}">
                    <Setter Property="Content" Value="{Binding Path=AlternationIndex, RelativeSource={RelativeSource AncestorType=DataGridRow}}" />
                </Style>
            </DataGrid.RowHeaderStyle>
        </DataGrid>

2

这是为新手或急于解决问题的人提供几乎可以复制和粘贴的示例答案(不鼓励这样做),灵感来自@GrantA和@Johan Larsson在此帖子中的回答(以及其他许多回答该主题的人)。

  • You may not want to add the enumeration inside a column
  • You do not need to re-create your own Attached Property

    <UserControl...
    
    <Grid>
        <DataGrid ItemsSource="{Binding MainData.ProjColl}" 
                  AutoGenerateColumns="False"
                  AlternationCount="{ Binding MainData.ProjColl.Count}" >
            <DataGrid.Columns>
                <!--Columns given here for example-->
                ...
                <DataGridTextColumn Header="Project Name" 
                                    Binding="{Binding CMProjectItemDirName}"
                                    IsReadOnly="True"/>
                ...
                <DataGridTextColumn Header="Sources Dir" 
                                    Binding="{Binding CMSourceDir.DirStr}"/>
                ...
            </DataGrid.Columns>
    
            <!--The problem of the day-->
            <DataGrid.RowHeaderStyle>
                <Style TargetType="{x:Type DataGridRowHeader}">
                    <Setter Property="Content" 
                     Value="{Binding Path=(ItemsControl.AlternationIndex),
                     RelativeSource={RelativeSource AncestorType=DataGridRow}}"/>
                </Style>
            </DataGrid.RowHeaderStyle>
        </DataGrid>
    </Grid>
    
    </UserControl>
    
请注意在 Fredrik Hedblad 在 Check if Row as odd number 中的回答中警告(ItemsControl.AlternationIndex)周围的括号()

enter image description here


0
使用附加属性,完整源代码 在这里
using System.Windows;
using System.Windows.Controls;

public static class Index
{
    private static readonly DependencyPropertyKey OfPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
        "Of",
        typeof(int),
        typeof(Index),
        new PropertyMetadata(-1));

    public static readonly DependencyProperty OfProperty = OfPropertyKey.DependencyProperty;

    public static readonly DependencyProperty InProperty = DependencyProperty.RegisterAttached(
        "In",
        typeof(DataGrid),
        typeof(Index),
        new PropertyMetadata(default(DataGrid), OnInChanged));

    public static void SetOf(this DataGridRow element, int value)
    {
        element.SetValue(OfPropertyKey, value);
    }

    public static int GetOf(this DataGridRow element)
    {
        return (int)element.GetValue(OfProperty);
    }

    public static void SetIn(this DataGridRow element, DataGrid value)
    {
        element.SetValue(InProperty, value);
    }

    public static DataGrid GetIn(this DataGridRow element)
    {
        return (DataGrid)element.GetValue(InProperty);
    }

    private static void OnInChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var row = (DataGridRow)d;
        row.SetOf(row.GetIndex());
    }
}

Xaml:

<DataGrid ItemsSource="{Binding Data}">
    <DataGrid.RowStyle>
        <Style TargetType="{x:Type DataGridRow}">
            <Setter Property="dataGrid2D:Index.In" 
                    Value="{Binding RelativeSource={RelativeSource AncestorType={x:Type DataGrid}}}" />
        </Style>
    </DataGrid.RowStyle>

    <DataGrid.RowHeaderStyle>
        <Style TargetType="{x:Type DataGridRowHeader}">
            <Setter Property="Content" 
                    Value="{Binding Path=(dataGrid2D:Index.Of), 
                                    RelativeSource={RelativeSource AncestorType={x:Type DataGridRow}}}" />
        </Style>
    </DataGrid.RowHeaderStyle>
</DataGrid>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接