Simple Way to Display Row Numbers on Wpf Datagrid

Simple way to display row numbers on WPF DataGrid

One way is to add them in the LoadingRow event for the DataGrid

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

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

When items are added or removed from the source list then the numbers can get out of sync for a while. For a fix to this, see the attached behavior here:

WPF 4 DataGrid: Getting the Row Number into the RowHeader

Useable like this

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

How to show row-number in first column of WPF Datagrid

There might be an easier way to do this but I got it to work by using the GetIndex() method on the DataGridRow class. This returns the index in to the data source so might not be exactly what you're after.

Sample Image

the xaml

  <Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:sys="clr-namespace:System;assembly=mscorlib"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525">
<DataGrid>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={local:RowToIndexConverter}}" />
</DataGrid.Columns>
<DataGrid.Items>
<sys:String>a</sys:String>
<sys:String>b</sys:String>
<sys:String>c</sys:String>
<sys:String>d</sys:String>
<sys:String>e</sys:String>
</DataGrid.Items>
</DataGrid>
</Window>

and the converter.

public class RowToIndexConverter : MarkupExtension, IValueConverter
{
static RowToIndexConverter converter;

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
DataGridRow row = value as DataGridRow;
if (row != null)
return row.GetIndex();
else
return -1;
}

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

public override object ProvideValue(IServiceProvider serviceProvider)
{
if (converter == null) converter = new RowToIndexConverter();
return converter;
}

public RowToIndexConverter()
{
}
}

Show row-number in DataGrid

One way is to add them in the LoadingRow event for the DataGrid

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

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

When items are added or removed from the source list then the numbers can get out of sync for a while

When items are added or removed from the source list then the numbers can get out of sync for a while.For a fix to this, see the attached behavior here:

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

use this instead if you want to count from 1

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

Hope this helps

How to display a certain number of rows in a DataGrid? (C#/WPF)

<DataGrid x:Name="CsvGrid" ColumnWidth="*" LoadingRow="CsvGrid_LoadingRow" ItemsSource="{Binding csvTable}" />

private void CsvGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.Header = (e.Row.GetIndex()+1).ToString();
if(e.Row.GetIndex() > _showRows - 1) e.Row.Visibility = Visibility.Hidden;
}

Simple way to display row numbers on WPF DataGrid

One way is to add them in the LoadingRow event for the DataGrid

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

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

When items are added or removed from the source list then the numbers can get out of sync for a while. For a fix to this, see the attached behavior here:

WPF 4 DataGrid: Getting the Row Number into the RowHeader

Useable like this

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

How to update row number in DataGrid (WPF)?

So, eventually I found solution here

https://ru.stackoverflow.com/a/853244/195957

Firstly you need to create such class

public class NumerRow : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
DataGridRow row = values[0] as DataGridRow;
if (row.DataContext?.GetType().FullName == "MS.Internal.NamedObject") return null;
return (row.GetIndex() + 1).ToString();
}

public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
=> throw new NotSupportedException();
}

And in .xalm

<DataGridTextColumn Header="№">
<DataGridTextColumn.Binding>
<MultiBinding Converter="{StaticResource NumerRow}">
<Binding Mode="OneWay" RelativeSource="{RelativeSource AncestorType={x:Type DataGridRow}}"/>
<Binding Mode="OneWay" RelativeSource="{RelativeSource AncestorType={x:Type DataGrid}}" Path="Items.Count"/>
</MultiBinding>
</DataGridTextColumn.Binding>
</DataGridTextColumn>

Result is

введите сюда описание изображения

WPF 4 DataGrid: Getting the Row Number into the RowHeader

One way is to add them in the LoadingRow event for the DataGrid.

<DataGrid Name="DataGrid" LoadingRow="DataGrid_LoadingRow" ... />
void DataGrid_LoadingRow(object sender, DataGridRowEventArgs e)
{
// Adding 1 to make the row count start at 1 instead of 0
// as pointed out by daub815
e.Row.Header = (e.Row.GetIndex() + 1).ToString();
}

Update
To get this to work with the .NET 3.5 DataGrid in WPF Toolkit a little modification is needed. The index is still generated correctly but the output fails when using virtualization. The following modification to the RowHeaderTemplate fixes this

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

Edit 2012-07-05
If items are added or removed from the source list then the numbers get out of sync until the list is scrolled so LoadingRow is called again. Working around this issue is a little more complex and the best solution I can think of right now is to keep the LoadingRow solution above and also

  • Subscribe to dataGrid.ItemContainerGenerator.ItemsChanged
  • In the event handler, find all the child DataGridRows in the visual tree
  • Set the Header to the index for each DataGridRow

Here is an attached behavior which does this. Use it like this

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

DisplayRowNumber

public class DataGridBehavior
{
#region DisplayRowNumber

public static DependencyProperty DisplayRowNumberProperty =
DependencyProperty.RegisterAttached("DisplayRowNumber",
typeof(bool),
typeof(DataGridBehavior),
new FrameworkPropertyMetadata(false, OnDisplayRowNumberChanged));
public static bool GetDisplayRowNumber(DependencyObject target)
{
return (bool)target.GetValue(DisplayRowNumberProperty);
}
public static void SetDisplayRowNumber(DependencyObject target, bool value)
{
target.SetValue(DisplayRowNumberProperty, value);
}

private static void OnDisplayRowNumberChanged(DependencyObject target, DependencyPropertyChangedEventArgs e)
{
DataGrid dataGrid = target as DataGrid;
if ((bool)e.NewValue == true)
{
EventHandler<DataGridRowEventArgs> loadedRowHandler = null;
loadedRowHandler = (object sender, DataGridRowEventArgs ea) =>
{
if (GetDisplayRowNumber(dataGrid) == false)
{
dataGrid.LoadingRow -= loadedRowHandler;
return;
}
ea.Row.Header = ea.Row.GetIndex();
};
dataGrid.LoadingRow += loadedRowHandler;

ItemsChangedEventHandler itemsChangedHandler = null;
itemsChangedHandler = (object sender, ItemsChangedEventArgs ea) =>
{
if (GetDisplayRowNumber(dataGrid) == false)
{
dataGrid.ItemContainerGenerator.ItemsChanged -= itemsChangedHandler;
return;
}
GetVisualChildCollection<DataGridRow>(dataGrid).
ForEach(d => d.Header = d.GetIndex());
};
dataGrid.ItemContainerGenerator.ItemsChanged += itemsChangedHandler;
}
}

#endregion // DisplayRowNumber

#region Get Visuals

private static List<T> GetVisualChildCollection<T>(object parent) where T : Visual
{
List<T> visualCollection = new List<T>();
GetVisualChildCollection(parent as DependencyObject, visualCollection);
return visualCollection;
}

private static void GetVisualChildCollection<T>(DependencyObject parent, List<T> visualCollection) where T : Visual
{
int count = VisualTreeHelper.GetChildrenCount(parent);
for (int i = 0; i < count; i++)
{
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
if (child is T)
{
visualCollection.Add(child as T);
}
if (child != null)
{
GetVisualChildCollection(child, visualCollection);
}
}
}

#endregion // Get Visuals
}

How can put Row number in DataGridRowHeader with out of conflict Row Header style

Is seems that in the default Template for DataGridRowHeader, there is no reference to HorizontalContentAlignment:

https://msdn.microsoft.com/en-us/library/ff506248(v=vs.110).aspx

look for:

<Style TargetType="{x:Type DataGridRowHeader}">

I would suggest you to override it's default Style and Template, so you can change the HorizontalAlignment of the Content.



Related Topics



Leave a reply



Submit