2011-09-06 45 views
0

考虑以下WPF/C#程序:显示和ListView中由不同的值进行排序

using System.Collections.Generic; 
using System.Windows; 
using System.Windows.Controls; 
using System.Windows.Data; 
using System.ComponentModel; 

namespace ListViewSorting 
{ 
    public partial class MainWindow : Window 
    { 
    public List<SomeClass> someList; 
    public List<SomeClass> SomeList 
    { 
     get { return someList; } 
     set { someList = value; } 
    } 

    public MainWindow() 
    { 
     this.DataContext = this; 
     someList = new List<SomeClass>(); 
     someList.Add(new SomeClass(123)); 
     someList.Add(new SomeClass(456)); 
     someList.Add(new SomeClass(789)); 

     InitializeComponent(); 
    } 

    GridViewColumnHeader _lastHeaderClicked = null; 
    ListSortDirection _lastDirection = ListSortDirection.Ascending; 

    private void listBox1_Click(object sender, RoutedEventArgs e) 
    { 
     someGridView.Columns.ToString(); 
     GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader; 
     ListSortDirection direction; 

     if (headerClicked != null) 
     { 
     if (headerClicked.Role != GridViewColumnHeaderRole.Padding) 
     { 
      if (headerClicked != _lastHeaderClicked) 
      { 
      direction = ListSortDirection.Ascending; 
      } 
      else 
      { 
      if (_lastDirection == ListSortDirection.Ascending) 
      { 
       direction = ListSortDirection.Descending; 
      } 
      else 
      { 
       direction = ListSortDirection.Ascending; 
      } 
      } 

      string header1 = headerClicked.Column.Header as string; 
      string header2 = (string)((Binding)((GridViewColumnHeader)e.OriginalSource).Column.DisplayMemberBinding).Path.Path; 
      Sort(header2, direction); 

      _lastHeaderClicked = headerClicked; 
      _lastDirection = direction; 
     } 
     } 
    } 

    private void Sort(string sortBy, ListSortDirection direction) 
    { 
     ICollectionView dataView = CollectionViewSource.GetDefaultView(someListView.ItemsSource); 

     dataView.SortDescriptions.Clear(); 
     SortDescription sd = new SortDescription(sortBy, direction); 
     dataView.SortDescriptions.Add(sd); 
     dataView.Refresh(); 
    } 
    } 

    public class SomeClass 
    { 
    private int someValue; 
    public int SomeValue 
    { 
     get { return someValue; } 
     set { someValue = value; } 
    } 
    public SomeClass(int someValue) 
    { 
     this.someValue = someValue; 
    } 
    public string StringValue 
    { 
     get 
     { 
     string str = someValue.ToString(); 
     string returnValue = string.Empty; 
     foreach (char someChar in str) 
     { 
      switch (someChar) 
      { 
      case '0': returnValue += "ZERO "; break; 
      case '1': returnValue += "ONE "; break; 
      case '2': returnValue += "TWO "; break; 
      case '3': returnValue += "THREE "; break; 
      case '4': returnValue += "FOUR "; break; 
      case '5': returnValue += "FIVE "; break; 
      case '6': returnValue += "SIX "; break; 
      case '7': returnValue += "SEVEN "; break; 
      case '8': returnValue += "EIGHT "; break; 
      case '9': returnValue += "NINE "; break; 
      default: returnValue += "UNKNOWN "; break; 
      } 
     } 
     return returnValue; 
     } 
    } 
    } 
} 

...和以下WPF:

<Window x:Class="ListViewSorting.MainWindow" 
     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
     Title="MainWindow" Height="350" Width="525"> 
    <Grid> 
     <StackPanel Orientation="Vertical"> 
      <ListView 
       x:Name="someListView" 
       Height="251" 
       HorizontalAlignment="Left" 
       GridViewColumnHeader.Click="listBox1_Click" 
       Margin="22,29,0,0" 
       VerticalAlignment="Top"     
       Width="453" 
       ItemsSource="{Binding SomeList}"> 

       <ListView.View> 
        <GridView x:Name="someGridView"> 
         <GridViewColumn Width="50" Header="SomeValue" DisplayMemberBinding="{Binding Path=SomeValue}" /> 
         <GridViewColumn Width="100" Header="StringValue" DisplayMemberBinding="{Binding Path=StringValue}" /> 
        </GridView> 
       </ListView.View> 
      </ListView> 
     </StackPanel> 
    </Grid> 
</Window> 

该代码创建对象的列表,每其中能够保存一个整数值。 WPF创建一个绑定到此列表的表,并在两个单独的列中显示列表中项目的数值和字符串值。因此,例如,对于整数值123,第一列将显示“123”,而第二列将显示“一两个三”。

单击第一列的标题正确地按照升序/降序对值进行排序。单击第二列的标题不会正确排序值,因为例如字符串'FOUR FIVE SIX''小于'字符串'ONE TWO THREE'。

我想第二列正确排序,换句话说,第二列显示类的'StringValue'字符串字段,但按'SomeValue'整数字段排序。

回答

1

如果您关心更具说明性的解决方案,您实际上可以创建自己的一些代码。这样,您就不必在窗口代码中添加事件处理程序代码。

首先创建像下面这样的类:

public class GridViewSorting 
{ 
    public static ICommand GetCommand(DependencyObject obj) { return (ICommand)obj.GetValue(CommandProperty); } 

    public static void SetCommand(DependencyObject obj, ICommand value) { obj.SetValue(CommandProperty, value); } 

    public static readonly DependencyProperty CommandProperty = 
     DependencyProperty.RegisterAttached(
      "Command", 
      typeof(ICommand), 
      typeof(GridViewSorting), 
      new UIPropertyMetadata(
       null, 
       (o, e) => 
       { 
        ItemsControl listView = o as ItemsControl; 
        if (listView != null) 
        { 
         if (!GetAutoSort(listView)) // Don't change click handler if AutoSort enabled 
         { 
          if (e.OldValue != null && e.NewValue == null) 
          { 
           listView.RemoveHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click)); 
          } 
          if (e.OldValue == null && e.NewValue != null) 
          { 
           listView.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click)); 
          } 
         } 
        } 
       } 
      ) 
     ); 

    public static bool GetAutoSort(DependencyObject obj) { return (bool)obj.GetValue(AutoSortProperty); } 

    public static void SetAutoSort(DependencyObject obj, bool value) { obj.SetValue(AutoSortProperty, value); } 

    public static readonly DependencyProperty AutoSortProperty = 
     DependencyProperty.RegisterAttached(
      "AutoSort", 
      typeof(bool), 
      typeof(GridViewSorting), 
      new UIPropertyMetadata(
       false, 
       (o, e) => 
       { 
        ListView listView = o as ListView; 
        if (listView != null) 
        { 
         if (GetCommand(listView) == null) // Don't change click handler if a command is set 
         { 
          bool oldValue = (bool)e.OldValue; 
          bool newValue = (bool)e.NewValue; 
          if (oldValue && !newValue) 
          { 
           listView.RemoveHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click)); 
          } 
          if (!oldValue && newValue) 
          { 
           listView.AddHandler(GridViewColumnHeader.ClickEvent, new RoutedEventHandler(ColumnHeader_Click)); 
          } 
         } 
        } 
       } 
      ) 
     ); 

    public static string GetPropertyName(DependencyObject obj) { return (string)obj.GetValue(PropertyNameProperty); } 

    public static void SetPropertyName(DependencyObject obj, string value) { obj.SetValue(PropertyNameProperty, value); } 

    public static readonly DependencyProperty PropertyNameProperty = 
     DependencyProperty.RegisterAttached(
      "PropertyName", 
      typeof(string), 
      typeof(GridViewSort), 
      new UIPropertyMetadata(null) 
     ); 

    private static void ColumnHeader_Click(object sender, RoutedEventArgs e) 
    { 
     GridViewColumnHeader headerClicked = e.OriginalSource as GridViewColumnHeader; 
     if (headerClicked != null) 
     { 
      string propertyName = GetPropertyName(headerClicked.Column); 
      if (!string.IsNullOrEmpty(propertyName)) 
      { 
       ListView listView = GetAncestor<ListView>(headerClicked); 
       if (listView != null) 
       { 
        ICommand command = GetCommand(listView); 
        if (command != null) 
        { 
         if (command.CanExecute(propertyName)) 
         { 
          command.Execute(propertyName); 
         } 
        } 
        else if (GetAutoSort(listView)) 
        { 
         ApplySort(listView.Items, propertyName); 
        } 
       } 
      } 
     } 
    } 

    public static T GetAncestor<T>(DependencyObject reference) where T : DependencyObject 
    { 
     DependencyObject parent = VisualTreeHelper.GetParent(reference); 
     while (!(parent is T)) 
     { 
      parent = VisualTreeHelper.GetParent(parent); 
     } 
     if (parent != null) 
      return (T)parent; 
     return null; 
    } 

    public static void ApplySort(ICollectionView view, string propertyName) 
    { 
     ListSortDirection direction = ListSortDirection.Ascending; 
     if (view.SortDescriptions.Count > 0) 
     { 
      SortDescription currentSort = view.SortDescriptions[0]; 
      if (currentSort.PropertyName == propertyName) 
      { 
       if (currentSort.Direction == ListSortDirection.Ascending) 
        direction = ListSortDirection.Descending; 
       else 
        direction = ListSortDirection.Ascending; 
      } 
      view.SortDescriptions.Clear(); 
     } 
     if (!string.IsNullOrEmpty(propertyName)) 
     { 
      view.SortDescriptions.Add(new SortDescription(propertyName, direction)); 
     } 
    } 
} 

之后,引用此类从顶层XAML节点驻留在命名空间:

xmlns:util="clr-namespace:MyApp.Util" 

最后,你可以使用这个类以声明方式设置sortkeys:

<GridViewColumn Header="StringRepresentation" 
       x:Name="valueColumn" 
       util:GridViewSort.PropertyName="NumericRepresentation"> 

我想我在StackOverflow上找到了这个解决方案abou一年前,抱歉不记得原来的提议者...

1

您将只需这样让你的结果:

private void Sort(string sortBy, ListSortDirection direction) 
     { 
      ICollectionView dataView = CollectionViewSource.GetDefaultView(someListView.ItemsSource); 

      dataView.SortDescriptions.Clear(); 

SortDescription sd = new SortDescription("SomeValue", direction); 

      dataView.SortDescriptions.Add(sd); 
      dataView.Refresh(); 
     } 

只是简单地把SortDescription第一个参数“someValue中”静电。