llenar example como column wpf wpfdatagrid

example - WPF 4 DataGrid: obtener el número de fila en el RowHeader



wpf datagrid example (5)

Estoy buscando obtener el número de fila en el RowHeader de WPF 4 DataGrid para que tenga una columna similar a Excel para los números de fila de DataGrid.

La solución que he visto en la web sugiere agregar un campo de índice a los objetos comerciales. Esta no es realmente una opción porque el DataGrid se volverá a pedir mucho y no queremos tener que hacer un seguimiento del cambio de estos campos de índice constantemente.

Muchas gracias


La respuesta de @Fredrik Hedblad funciona para mí. ¡Gracias!

Agregué otra propiedad para obtener un valor de "compensación" para que DataGrid pueda comenzar desde 0 o 1 (o lo que sea que esté configurado).

Para usar el comportamiento, (nota ''b'' es el espacio de nombres)

<DataGrid ItemsSource="{Binding ...}" b:DataGridBehavior.DisplayRowNumberOffset="1" b:DataGridBehavior.DisplayRowNumber="True">

Las clases modificadas:

/// <summary> /// Collection of DataGrid behavior /// </summary> public static class DataGridBehavior { #region DisplayRowNumberOffset /// <summary> /// Sets the starting value of the row header if enabled /// </summary> public static DependencyProperty DisplayRowNumberOffsetProperty = DependencyProperty.RegisterAttached("DisplayRowNumberOffset", typeof(int), typeof(DataGridBehavior), new FrameworkPropertyMetadata(0, OnDisplayRowNumberOffsetChanged)); public static int GetDisplayRowNumberOffset(DependencyObject target) { return (int)target.GetValue(DisplayRowNumberOffsetProperty); } public static void SetDisplayRowNumberOffset(DependencyObject target, int value) { target.SetValue(DisplayRowNumberOffsetProperty, value); } private static void OnDisplayRowNumberOffsetChanged(DependencyObject target, DependencyPropertyChangedEventArgs e) { DataGrid dataGrid = target as DataGrid; int offset = (int)e.NewValue; if (GetDisplayRowNumber(target)) { WPFUtil.GetVisualChildCollection<DataGridRow>(dataGrid). ForEach(d => d.Header = d.GetIndex() + offset); } } #endregion #region DisplayRowNumber /// <summary> /// Enable display of row header automatically /// </summary> /// <remarks> /// Source: /// </remarks> 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) { int offset = GetDisplayRowNumberOffset(target); EventHandler<DataGridRowEventArgs> loadedRowHandler = null; loadedRowHandler = (object sender, DataGridRowEventArgs ea) => { if (GetDisplayRowNumber(dataGrid) == false) { dataGrid.LoadingRow -= loadedRowHandler; return; } ea.Row.Header = ea.Row.GetIndex() + offset; }; dataGrid.LoadingRow += loadedRowHandler; ItemsChangedEventHandler itemsChangedHandler = null; itemsChangedHandler = (object sender, ItemsChangedEventArgs ea) => { if (GetDisplayRowNumber(dataGrid) == false) { dataGrid.ItemContainerGenerator.ItemsChanged -= itemsChangedHandler; return; } WPFUtil.GetVisualChildCollection<DataGridRow>(dataGrid). ForEach(d => d.Header = d.GetIndex() + offset); }; dataGrid.ItemContainerGenerator.ItemsChanged += itemsChangedHandler; } } #endregion // DisplayRowNumber }


LoadingRowEvent se desencadena por esto:

ICollectionView view = CollectionViewSource.GetDefaultView(_dataGrid.ItemsSource); view.Refresh();


Todos estos enfoques no funcionarán si agrega o elimina filas. Debe actualizar los índices de fila en tales casos. Mira este comportamiento:

public static class DataGridBehavior { #region RowNumbers property public static readonly DependencyProperty RowNumbersProperty = DependencyProperty.RegisterAttached("RowNumbers", typeof (bool), typeof (DataGridBehavior), new FrameworkPropertyMetadata(false, OnRowNumbersChanged)); private static void OnRowNumbersChanged(DependencyObject source, DependencyPropertyChangedEventArgs args) { DataGrid grid = source as DataGrid; if (grid == null) return; if ((bool)args.NewValue) { grid.LoadingRow += onGridLoadingRow; grid.UnloadingRow += onGridUnloadingRow; } else { grid.LoadingRow -= onGridLoadingRow; grid.UnloadingRow -= onGridUnloadingRow; } } private static void refreshDataGridRowNumbers(object sender) { DataGrid grid = sender as DataGrid; if (grid == null) return; foreach (var item in grid.Items) { var row = (DataGridRow)grid.ItemContainerGenerator.ContainerFromItem(item); if (row != null) row.Header = row.GetIndex() + 1; } } private static void onGridUnloadingRow(object sender, DataGridRowEventArgs e) { refreshDataGridRowNumbers(sender); } private static void onGridLoadingRow(object sender, DataGridRowEventArgs e) { refreshDataGridRowNumbers(sender); } [AttachedPropertyBrowsableForType(typeof(DataGrid))] public static void SetRowNumbers(DependencyObject element, bool value) { element.SetValue(RowNumbersProperty, value); } public static bool GetRowNumbers(DependencyObject element) { return (bool) element.GetValue(RowNumbersProperty); } #endregion }


Edición: al parecer, el desplazamiento cambia el índice para que el enlace no funcione así ...

Una solución de plantillas (aparentemente) limpia:
Xaml:

<Window ... xmlns:local="clr-namespace:Test" DataContext="{Binding RelativeSource={RelativeSource Mode=Self}}"> <Window.Resources> <local:RowToIndexConv x:Key="RowToIndexConv"/> </Window.Resources> <DataGrid ItemsSource="{Binding GridData}"> <DataGrid.RowHeaderTemplate> <DataTemplate> <TextBlock Margin="2" Text="{Binding RelativeSource={RelativeSource AncestorType=DataGridRow}, Converter={StaticResource RowToIndexConv}}"/> </DataTemplate> </DataGrid.RowHeaderTemplate> </DataGrid> </Window>

Convertidor:

public class RowToIndexConv : IValueConverter { #region IValueConverter Members public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { DataGridRow row = value as DataGridRow; return row.GetIndex() + 1; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } #endregion }


Una forma es agregarlos en el evento LoadingRow para el 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(); }

Actualizar
Para que esto funcione con .NET 3.5 DataGrid en WPF Toolkit, se necesita una pequeña modificación. El índice aún se genera correctamente pero la salida falla cuando se usa la virtualización. La siguiente modificación de RowHeaderTemplate soluciona esto

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

Editar 2012-07-05
Si se agregan o eliminan elementos de la lista de origen, los números LoadingRow sincronización hasta que la lista se desplaza para que se LoadingRow llamar a LoadingRow . Resolver este problema es un poco más complejo y la mejor solución que se me ocurre ahora es mantener la solución LoadingRow arriba y también

  • Suscribirse a dataGrid.ItemContainerGenerator.ItemsChanged
  • En el controlador de eventos, busque todos los DataGridRows secundarios en el árbol visual
  • Establezca el encabezado en el índice para cada DataGridRow

Aquí hay un comportamiento adjunto que hace esto. Usalo asi

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