2009-04-13 80 views
22

我有一個排序列表框,需要顯示每個項目的行編號。在這個演示中,我有一個名爲字符串屬性的Person類。列表框顯示按姓名排序的人員列表。如何添加到列表框的數據模板行號?編號列表框

XAML:

<Window x:Class="NumberedListBox.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Height="300" Width="300"> 
    <ListBox 
     ItemsSource="{Binding Path=PersonsListCollectionView}" 
     HorizontalContentAlignment="Stretch"> 
     <ListBox.ItemTemplate> 
      <DataTemplate> 
       <TextBlock Text="{Binding Path=Name}" /> 
      </DataTemplate> 
     </ListBox.ItemTemplate> 
    </ListBox> 
</Window> 

後面的代碼:

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<Person>(); 
      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<Person> Persons { get; private set; } 
     public ListCollectionView PersonsListCollectionView { get; private set; } 
    } 

    public class Person 
    { 
     public string Name { get; set; } 
    } 
} 

回答

3

大衛布朗鏈接中的想法是使用一個工作的價值轉換器。以下是一個完整的工作示例。列表框具有行號,可以按姓名和年齡進行排序。

XAML:

<Window x:Class="NumberedListBox.Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:NumberedListBox" 
    Height="300" Width="300"> 

    <Window.Resources> 

     <local:RowNumberConverter x:Key="RowNumberConverter" /> 

     <CollectionViewSource x:Key="sortedPersonList" Source="{Binding Path=Persons}" /> 

    </Window.Resources> 

    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition /> 
      <RowDefinition Height="Auto"/> 
     </Grid.RowDefinitions> 
     <Grid.ColumnDefinitions> 
      <ColumnDefinition /> 
      <ColumnDefinition /> 
     </Grid.ColumnDefinitions> 
     <ListBox 
      Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" 
      ItemsSource="{Binding Source={StaticResource sortedPersonList}}" 
      HorizontalContentAlignment="Stretch"> 
      <ListBox.ItemTemplate> 
       <DataTemplate> 
        <StackPanel Orientation="Horizontal"> 
         <TextBlock 
          Text="{Binding Converter={StaticResource RowNumberConverter}, ConverterParameter={StaticResource sortedPersonList}}" 
          Margin="5" /> 
         <TextBlock Text="{Binding Path=Name}" Margin="5" /> 
         <TextBlock Text="{Binding Path=Age}" Margin="5" /> 
        </StackPanel> 
       </DataTemplate> 
      </ListBox.ItemTemplate> 
     </ListBox> 
     <Button Grid.Row="1" Grid.Column="0" Content="Name" Tag="Name" Click="SortButton_Click" /> 
     <Button Grid.Row="1" Grid.Column="1" Content="Age" Tag="Age" Click="SortButton_Click" /> 
    </Grid> 
</Window> 

後面的代碼:

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<Person>(); 
      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<Person> 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; } 
    } 
} 

值轉換器:

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(); 
     } 
    } 
} 
+12

呃,是不是會導致N^2行爲?對於屏幕上的每個項目,遍歷所有可能的項目以查找當前項目索引的索引。 – Armentage 2011-05-29 22:15:18

46

終於來了!如果找到一種更優雅的方式,可能性能更好。 (另請參閱Accessing an ItemsControl item as it is added

我們對此屬性「誤用」屬性ItemsControl.AlternateIndex。最初它旨在以不同的方式處理ListBox中的每一行。 (見http://msdn.microsoft.com/en-us/library/system.windows.controls.itemscontrol.alternationcount.aspx

1.設置AlternatingCount包含ListBox中的項目金額

<ListBox ItemsSource="{Binding Path=MyListItems}" 
     AlternationCount="{Binding Path=MyListItems.Count}" 
     ItemTemplate="{StaticResource MyItemTemplate}" 
... 
/> 

2.綁定到AlternatingIndex您的DataTemplate

<DataTemplate x:Key="MyItemTemplate" ... > 
    <StackPanel> 
     <Label Content="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplatedParent.(ItemsControl.AlternationIndex)}" /> 
     ... 
    </StackPanel> 
</DataTemplate> 

所以這個工作沒有一個轉換器,額外的CollectionViewSource,最重要的是沒有蠻力搜索源集合。

+0

@yhw:謝謝,找到了解決辦法... – Seven 2010-09-16 18:38:11

2

又一個答案。我嘗試了WPF(AlternationCount解決方案)中的上述工作,但我需要Silverlight代碼,所以我做了以下工作。這比其他的蠻力方法更優雅。

<UserControl xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    xmlns:local="clr-namespace:RowNumber" x:Name="userControl" 
    x:Class="RowNumber.MainPage" Width="640" Height="480"> 
<Grid x:Name="LayoutRoot" Background="White"> 
    <ListBox ItemsSource="{Binding Test, ElementName=userControl}"> 
    <ListBox.Resources> 
     <local:ListItemIndexConverter x:Key="IndexConverter" /> 
    </ListBox.Resources> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <StackPanel Orientation="Horizontal"> 
       <TextBlock Width="30" 
        Text="{Binding RelativeSource={RelativeSource AncestorType=ListBoxItem}, Converter={StaticResource IndexConverter}}" /> 
       <TextBlock Text="{Binding}" /> 
      </StackPanel> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
    </ListBox> 
</Grid> 
</UserControl> 

背後

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<ListBox>().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<string> Test { get { return new[] { "Foo", "Bar", "Baz" }.ToList(); } } 
    } 
    } 

這是新的可用在Silverlight 5引入RelativeSource結合。

-1

爲什麼不只是綁定到listbox的count屬性。

<ListView x:Name="LstFocusImageDisplayData" 

          > 
        <ListView.ItemTemplate> 
         <DataTemplate> 
          <GroupBox Header="Item Count"> 
           <DockPanel> 
            <TextBlock Text="{Binding ElementName=LstFocusImageDisplayData, Path=Items.Count, Mode=OneTime}" /> 
           </DockPanel> 
          </GroupBox> 

         </DataTemplate> 
        </ListView.ItemTemplate> 
       </ListView>