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.
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
How to Change Listbox Selection Background Color
Correlation of Two Arrays in C#
Implementing the Producer/Consumer Pattern in C#
Change File Extension Using C#
Binary to Corresponding Ascii String Conversion
Getting Hwnd Off of Corewindow Object in Uwp
Static and Instance Methods with the Same Name
The Limitation on the Size of .Net Array
Add Vertical Scroll Bar to Panel
Entity Framework Ef.Functions.Like VS String.Contains
Get Table-Data from Table-Name in Linq Datacontext
Alternative to Multiple String.Replaces
Problems Overwriting (Re-Saving) Image When It Was Set as Image Source
How to Retain Callsite Information When Wrapping Nlog
Using Linq Except Not Working as I Thought
How to Make Texture2D Readable via Script
Is That Possible to Send Httpwebrequest Using Tls1.2 on .Net 4.0 Framework