2011-09-06 15 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中」靜電。

相關問題