Listbox numerado

Tengo un cuadro de lista ordenado y necesito mostrar el número de fila de cada artículo. En esta demostración, tengo una clase de persona con una propiedad de cadena de nombre. El cuadro de lista muestra una lista de Personas ordenadas por nombre. ¿Cómo puedo agregar a la plantilla de datos del cuadro de lista el número de fila?

XAML:

         

Código detrás:

 using System; using System.Collections.ObjectModel; using System.Windows.Data; using System.Windows; using System.ComponentModel; namespace NumberedListBox { public partial class Window1 : Window { public Window1() { InitializeComponent(); Persons = new ObservableCollection(); Persons.Add(new Person() { Name = "Sally"}); Persons.Add(new Person() { Name = "Bob" }); Persons.Add(new Person() { Name = "Joe" }); Persons.Add(new Person() { Name = "Mary" }); PersonsListCollectionView = new ListCollectionView(Persons); PersonsListCollectionView.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); DataContext = this; } public ObservableCollection Persons { get; private set; } public ListCollectionView PersonsListCollectionView { get; private set; } } public class Person { public string Name { get; set; } } } 

Esto debería comenzar:

http://weblogs.asp.net/hpreishuber/archive/2008/11/18/rownumber-in-silverlight-datagrid-or-listbox.aspx

Dice que es para Silverlight, pero no veo por qué no funcionaría para WPF. Básicamente, vincula un TextBlock a sus datos y utiliza un convertidor de valor personalizado para generar el número del elemento actual.

¡Finalmente! Si se encuentra de una manera mucho más elegante y, probablemente, con un mejor rendimiento tampoco. (Consulte también Acceder a un elemento de Control de elementos a medida que se agrega )

Nosotros ” ItemsControl.AlternateIndex ” la propiedad ItemsControl.AlternateIndex para esto. Originalmente, está diseñado para manejar cada dos filas dentro de un ListBox diferente. (vea http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.alternationcount.aspx )

1. Establezca AlternatingCount a la cantidad de elementos contenidos en el ListBox

  

2. Enlace a AlternatingIndex su DataTemplate

    ...   

Así que esto funciona sin un convertidor, un CollectionViewSource adicional y lo más importante sin una búsqueda de fuerza bruta en la colección fuente.

La idea en el enlace de David Brown era usar un convertidor de valor que funcionó. A continuación se muestra una muestra completa de trabajo. El cuadro de lista tiene números de fila y se puede ordenar tanto por nombre como por antigüedad.

XAML:

                              

Código detrás:

 using System; using System.Collections.ObjectModel; using System.Windows.Data; using System.Windows; using System.ComponentModel; using System.Windows.Controls; namespace NumberedListBox { public partial class Window1 : Window { public Window1() { InitializeComponent(); Persons = new ObservableCollection(); Persons.Add(new Person() { Name = "Sally", Age = 34 }); Persons.Add(new Person() { Name = "Bob", Age = 18 }); Persons.Add(new Person() { Name = "Joe", Age = 72 }); Persons.Add(new Person() { Name = "Mary", Age = 12 }); CollectionViewSource view = FindResource("sortedPersonList") as CollectionViewSource; view.SortDescriptions.Add(new SortDescription("Name", ListSortDirection.Ascending)); DataContext = this; } public ObservableCollection Persons { get; private set; } private void SortButton_Click(object sender, RoutedEventArgs e) { Button button = sender as Button; string sortProperty = button.Tag as string; CollectionViewSource view = FindResource("sortedPersonList") as CollectionViewSource; view.SortDescriptions.Clear(); view.SortDescriptions.Add(new SortDescription(sortProperty, ListSortDirection.Ascending)); view.View.Refresh(); } } public class Person { public string Name { get; set; } public int Age { get; set; } } } 

Convertidor de valor:

 using System; using System.Windows.Data; namespace NumberedListBox { public class RowNumberConverter : IValueConverter { public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { CollectionViewSource collectionViewSource = parameter as CollectionViewSource; int counter = 1; foreach (object item in collectionViewSource.View) { if (item == value) { return counter.ToString(); } counter++; } return string.Empty; } public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) { throw new NotImplementedException(); } } } 

Aún otra respuesta. Intenté lo anterior, que funciona en WPF (solución AlternationCount ), pero necesitaba código para Silverlight, así que hice lo siguiente. Esto es más elegante que el otro método de fuerza bruta.

                  

Y detrás

  using System; using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Data; namespace RowNumber { public class ListItemIndexConverter : IValueConverter { // Value should be ListBoxItem that contains the current record. RelativeSource={RelativeSource AncestorType=ListBoxItem} public object Convert(object value, Type targetType, object parameter, CultureInfo culture) { var lbi = (ListBoxItem)value; var listBox = lbi.GetVisualAncestors().OfType().First(); var index = listBox.ItemContainerGenerator.IndexFromContainer(lbi); // One based. Remove +1 for Zero based array. return index + 1; } public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) { throw new NotImplementedException(); } } public partial class MainPage : UserControl { public MainPage() { // Required to initialize variables InitializeComponent(); } public List Test { get { return new[] { "Foo", "Bar", "Baz" }.ToList(); } } } } 

Esto está disponible recientemente en Silverlight 5 con la introducción de enlace RelativeSource .

¿Por qué no solo vinculante para contar la propiedad del listbox?