web-dev-qa-db-fra.com

Un moyen simple d'afficher les numéros de ligne sur WPF DataGrid

Je veux juste afficher les numéros de ligne dans la colonne la plus à gauche de ma DataGrid. Y at-il un attribut pour faire cela?

Gardez à l'esprit, ce n'est pas une clé primaire pour ma table. Je ne veux pas que ces numéros de ligne se déplacent avec leurs lignes lorsqu'une colonne est triée. Je veux fondamentalement un compte courant. Il n'a même pas besoin d'avoir un en-tête.

22
JohnB

Une solution consiste à les ajouter à l'événement LoadingRow pour le contrôle DataGrid.

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

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

Lorsque des éléments sont ajoutés ou supprimés de la liste source, les numéros peuvent être désynchronisés pendant un certain temps. Pour résoudre ce problème, voir le comportement ci-joint ici:
WPF 4 DataGrid: Obtenir le numéro de la ligne dans le RowHeader

Utilisable comme ça

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

Ajouter une petite info sur la réponse de Fredrik Hedblad.

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

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

... Si vous voulez commencer à numéroter à partir de 1

9
JohnnyJaxs

Si votre grille de données a son ItemsSource lié à une collection, liez la propriété AlternationCount de votre grille de données à la propriété count de votre collection ou à la propriété Items.Count de votre DataGrid comme suit:

<DataGrid ItemsSource="{Binding MyObservableCollection}" AlternationCount="{Binding MyObservableCollection.Count}" />

Ou:

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

Soit devrait fonctionner.

Ensuite, en supposant que vous utilisiez un DataGridTextColumn pour votre colonne la plus à gauche, procédez comme suit dans votre définition DataGrid.Columns:

<DataGrid.Columns>
   <DataGridTextColumn Binding="{Binding AlternationIndex, RelativeSource={RelativeSource AncestorType=DataGridRow}}"
</DataGrid.Columns>

Si vous ne voulez pas commencer à 0, vous pouvez ajouter un convertisseur à votre liaison pour incrémenter l'index.

6
GrantA

Et juste pour ajouter à la discussion à ce sujet ... (j'ai passé trop de temps à le découvrir!).

Vous devez définir EnableRowVirtualization sur False dans la grille de données pour éviter les erreurs dans le séquencement des lignes: 

EnableRowVirtualization="False"

La propriété EnableRowVirtualization est définie sur true par défaut. Lorsque la propriété EnableRowVirtualization est définie sur true, le contrôle de données n'instancie pas d'objet DataGridRow pour chaque élément de données de la source de données liée. Au lieu de cela, le DataGrid crée des objets DataGridRow uniquement lorsqu'ils sont nécessaires et les réutilise autant que possible. Référence MSDN ici

4
P_Fitz

C'est une vieille question, mais j'aimerais partager quelque chose. J'ai eu un problème similaire, tout ce dont j'avais besoin était une simple numérotation RowHeader et la réponse de Fredrik Hedblad était presque complète pour mon problème.

Alors que c'est génial:

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

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

mes en-têtes foirés lors du retrait et de l'ajout d'éléments. Si vous avez des boutons responsables de cela, ajoutez simplement dataGrid.Items.Refresh(); sous le code de «suppression», comme dans mon cas:

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

    dataGrid.Items.Refresh();
}

La numérotation désyncronisée résolue pour moi, car l'actualisation des éléments appelle à nouveau DataGrig_LoadingRow.

2
trollsteen

Juste une autre réponse pour fournir un exemple presque copié-collé (à ne pas encourager) pour les nouvelles personnes ou les personnes pressées, inspirée par les réponses contenues dans ce message de @GrantA et @Johan Larsson (+ de nombreuses autres personnes ayant répondu aux nombreux messages sur ce sujet )

  • Vous pouvez ne pas vouloir ajouter l'énumération à l'intérieur d'une colonne
  • Vous n'avez pas besoin de recréer votre propre propriété attachée.

    <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>
    

Notez la parenthèse () autour de (ItemsControl.AlternationIndex) comme indiqué dans Fredrik Hedblad répond dans Check if Row comme nombre impair

 enter image description here

2
NGI

En utilisant les propriétés attachées, source complète ici

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>
0
Johan Larsson