Existen varios enfouqes para mostrar el número de fila en controles como DataGrid bajo el patrón MVVM. El más común es manejar el evento LoadingRow en el code-behind:
private void DataGridSoftware_LoadingRow(object sender, DataGridRowEventArgs e)
{
e.Row.Header = e.Row.GetIndex() + 1;
}
Sin embargo, esto rompe con MVVM y requiere lógica adicional si la lista se actualiza dinámicamente.
Otra opción es agregar una propiedad Indice en el ViewModel:
public class DatosViewModel : ObservableObject
{
private string _Nombre;
public string Nombre
{
get { return _Nombre; }
set { _Nombre = value; OnPropertyChanged("Nombre"); }
}
private int _Indice;
public int Indice
{
get { return _Indice; }
set { _Indice = value; OnPropertyChanged("Indice"); }
}
}
Esto obliga a actualizar manualmente el índice en cadda operación de la colección, lo cual es tedioso y propenso a errores.
Tras probar varias alternativas, encontré una solución elegante usando CollectionViewSource y un IValueConverter. La clave está en que CollectionViewSource proporciona una vista con ordenamiento, filtrado y agrupación automáticos, y su método IndexOf devuelve la posición actual del elemento.
El conversor recibe el elemento y la vista, y devuelve el número de fila:
[ValueConversion(typeof(object), typeof(int))]
public class ConvertidorFilaAIndice : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
int indice = 0;
var vistaOrigen = parameter as CollectionViewSource;
if (vistaOrigen != null)
{
CollectionView vista = (CollectionView)vistaOrigen.View;
indice = vista.IndexOf(value) + 1;
}
return indice > 0 ? indice : DependencyProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
=> throw new NotImplementedException();
}
En XAML se declara el CollectionViewSource y se usa el conversor en el estilo del encabezado de fila del DataGrid:
<Window.Resources>
<converter:ConvertidorFilaAIndice x:Key="convertidorIndice"/>
<CollectionViewSource Source="{Binding DatosPrincipales}" x:Key="vistaDatos"/>
</Window.Resources>
<Grid>
<DataGrid RowHeaderWidth="40" ItemsSource="{Binding Source={StaticResource vistaDatos}}">
<DataGrid.RowHeaderStyle>
<Style TargetType="{x:Type DataGridRowHeader}">
<Setter Property="Content"
Value="{Binding Converter={StaticResource convertidorIndice},
ConverterParameter={StaticResource vistaDatos}}"/>
</Style>
</DataGrid.RowHeaderStyle>
<DataGrid.Columns>
</DataGrid.Columns>
</DataGrid>
</Grid>
El flujo es simple:
- La fuente de datos real se expone como
CollectionViewSource, que administra internamente el orden y las posiciones. - El conversor usa
IndexOfde la vista para obtener la posición actual (empezando desde 1). - Como
CollectionViewSourcese actualiza automáticamente al cambiar la colección subyacente, los números de fila siempre son correctos sin manipulación manual.
Este enfoque respeta MVVM, es simple y funciona con cualquier control que herede de ItemsControl (DataGrid, ListBox, ListView, etc.).