2013-02-16 45 views
1

我有什么应用滤镜上的排序的ListCollectionView /的ObservableCollection

我已经做了TextBoxListBoxUserControlListBoxItemsSource通过ListCollectionView通过ListCollectionView绑定到ObservableCollectionDataContext,使用自定义排序和过滤器,我们将在下面看到。控制的目的是仅在ListBox中显示源集合中包含TextBox中文本的项目(string)。为此,我在ListCollectionView上应用了一个过滤器。

我有两个额外的限制。 1,我的原始集合未按字母顺序排序,但显示在ListBox中的项目正在使用ListCollectionViewCustomSort。 2,我必须只显示与TextBox中的字符串相匹配的前5项(按字母顺序排序)。我为此在ListCollectionView上应用了一个过滤器。

期望

比方说,我的收藏更是这样定义我DataContext

this.AllItems = new ObservableCollection<string> 
{ 
    "Banana", 
    "Watermelon", 
    "Peach", 
    "Grape", 
    "Apple", 
    "Pineapple", 
    "Cherry", 
    "Durian", 
    "Rambutan", 
    "Strawberry", 
    "Raspberry", 
    "Lemon", 
    "Orange", 
    "Sugar cane", 
    "Guava", 
    "Tomato", 
    "Coconut", 
    "Melon", 
    "Äpple", 
    "Glaçon", 
    "Etape", 
    "Étape" 
}; 

在我TextBox我输入字母“E”(完成所有的比较都是区分insenstive) 。我希望ListBox显示以下5个项目(CurrentUICulture设置为FR-FR):

  • 苹果
  • 苹果
  • 樱桃
  • Etape酒店
  • ETAPE

因为它们是按字母顺序排列时包含字母'e'的前5个项目。但是我得到了我的应用程序的下列项目:

  • 苹果
  • 葡萄
  • 菠萝
  • 西瓜

,因为他们是我的集合中的第5项包含字母'e'然后按字母顺序排序。

我的代码

下面就来了解我和我的问题的代码。 它应该几乎只使用下面的副本/粘贴(谨防名称空间和CurrentUICulture)。我正在使用C#4.0。

1)用作DataContext

public class FoobarViewModel : INotifyPropertyChanged 
{ 
    private ObservableCollection<string> allItems; 
    public event PropertyChangedEventHandler PropertyChanged; 

    public FoobarViewModel() 
    { 
     this.AllItems = new ObservableCollection<string> 
     { 
      "Banana", 
      "Watermelon", 
      "Peach", 
      "Grape", 
      "Apple", 
      "Pineapple", 
      "Cherry", 
      "Durian", 
      "Rambutan", 
      "Strawberry", 
      "Raspberry", 
      "Lemon", 
      "Orange", 
      "Sugar cane", 
      "Guava", 
      "Tomato", 
      "Coconut", 
      "Melon", 
      "Äpple", 
      "Glaçon", 
      "Etape", 
      "Étape" 
     }; 
    } 

    public ObservableCollection<string> AllItems 
    { 
     get 
     { 
      return this.allItems; 
     } 
     set 
     { 
      this.allItems = value; 
      this.OnPropertyChanged("AllItems"); 
     } 
    } 

    private void OnPropertyChanged(string propertyName) 
    { 
     var handler = this.PropertyChanged; 
     if (handler != null) 
     { 
      handler(this, new PropertyChangedEventArgs(propertyName)); 
     } 
    } 
} 

3)的我的UserControl

<UserControl x:Class="MyNamespace.Foobar" 
      xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
      xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
      xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
      mc:Ignorable="d" 
      d:DesignHeight="300" d:DesignWidth="300"> 
    <Grid> 
     <Grid.RowDefinitions> 
      <RowDefinition/> 
      <RowDefinition/> 
     </Grid.RowDefinitions> 

     <TextBox x:Name="textbox" Grid.Row="0"/> 
     <ListBox x:Name="listbox" Grid.Row="1"/> 
    </Grid> 
</UserControl> 

4)最后,大多数的XAML的MainWindow

<Window x:Class="MyNamespace.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" 
     xmlns:local="clr-namespace:MyNamespace"> 
    <Window.Resources> 
     <local:FoobarViewModel x:Key="Foobar"/> 
    </Window.Resources> 
    <StackPanel> 
     <local:Foobar DataContext="{StaticResource Foobar}" AllItems="{Binding AllItems}"/> 
    </StackPanel> 
</Window> 

2)类重要的是我的UserControl背后的代码。

public partial class Foobar : UserControl 
{ 
    #region Fields 
    public static readonly DependencyProperty AllItemsProperty = DependencyProperty.Register(
     "AllItems", 
     typeof(IEnumerable<string>), 
     typeof(Foobar), 
     new PropertyMetadata(AllItemsChangedCallback)); 

    private const int MaxItems = 5; 
    #endregion 

    #region Constructors 
    public Foobar() 
    { 
     InitializeComponent(); 

     textbox.KeyUp += TextboxKeyUp; 
    } 
    #endregion 

    #region Properties 
    public IEnumerable<string> AllItems 
    { 
     get { return (IEnumerable<string>)this.GetValue(AllItemsProperty); } 
     set { this.SetValue(AllItemsProperty, value); } 
    } 
    #endregion 

    #region Methods 
    private void TextboxKeyUp(object sender, KeyEventArgs e) 
    { 
     TextBox localTextBox = sender as TextBox; 
     if (localTextBox != null) 
     { 
      var items = ((ListCollectionView)listbox.ItemsSource).SourceCollection; 

      if (items.Cast<string>().Any(x => x.ToLower(CultureInfo.CurrentUICulture).Contains(localTextBox.Text.ToLower(CultureInfo.CurrentUICulture)))) 
      { 
       this.ApplyFilter(); 
       listbox.Visibility = Visibility.Visible; 
      } 
      else 
      { 
       listbox.Visibility = Visibility.Collapsed; 
      } 
     } 
    } 

    private static void AllItemsChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
    { 
     Foobar control = sender as Foobar; 
     if (control != null) 
     { 
      List<string> source = new List<string>((IEnumerable<string>)e.NewValue); 

      ListCollectionView view = (ListCollectionView)CollectionViewSource.GetDefaultView(source); 
      view.CustomSort = new CustomSort(); 
      control.listbox.ItemsSource = view; 
      control.ApplyFilter(); 
     } 
    } 

    private void ApplyFilter() 
    { 
     ListCollectionView view = (ListCollectionView)listbox.ItemsSource; 

     int index = 0; 
     view.Filter = x => 
     { 
      bool result = x.ToString().ToLower(CultureInfo.CurrentUICulture).Contains(textbox.Text.ToLower(CultureInfo.CurrentUICulture)); 
      if (result) 
      { 
       index++; 
      } 

      return index <= MaxItems && result; 
     }; 
    } 
    #endregion 

    private class CustomSort : IComparer 
    { 
     public int Compare(object x, object y) 
     { 
      return String.Compare(x.ToString(), y.ToString(), CultureInfo.CurrentUICulture, CompareOptions.IgnoreCase); 
     } 
    } 
} 

整个代码按预期方式工作,除了它在ApplyFilter方法进行的滤波。基本上,这种方法只是检查集合中的每个项目与TextBox中的任何项目,并且如果没有超过返回项目的最大数量,该项目将包含在过滤器中。当我调试此方法时,我可以看到项目按集合的原始顺序浏览,而不按排序顺序浏览,尽管过滤器似乎是在ListCollectionView而不是ObservableCollection<string>上完成的。

看来过滤器是先应用,然后是排序。我希望排序先应用然后过滤。

我的问题

我怎样才能应用滤镜上的排序ListCollectionView,而不是原来的非分类收集?

回答

1

为什么不创建通用的IComparer<T>并在创建集合视图之前使用Enumerable.OrderBy<TSource, TKey>(IEnumerable<TSource>, Func<TSource, TKey>, IComparer<TKey>)扩展方法。

所以,你最终的东西,如:

private static void AllItemsChangedCallback(DependencyObject sender, DependencyPropertyChangedEventArgs e) 
{ 
    Foobar control = sender as Foobar; 
    if (control != null) 
    { 
     var newEnumerable = (IEnumerable<string>)e.NewValue; 
     var sorted = newEnumerable.OrderBy(s => s, new CustomSort()); 
     var source = new List<string>(sorted); 

     var view = (ListCollectionView)CollectionViewSource.GetDefaultView(source); 
     control.listbox.ItemsSource = view; 
     control.ApplyFilter(); 
    } 
} 

private class CustomSort : IComparer<string> 
{ 
    public int Compare(string x, string y) 
    { 
     return String.Compare(x, y, CultureInfo.CurrentUICulture, CompareOptions.IgnoreCase); 
    } 
} 

然后您的收藏视图已经排序,可用于过滤。

+0

男人,你的解决方案是如此简单,但它工作得很好!已经3天了,我试图找出一个解决方案,不能接受任何东西......非常感谢! – Guillaume 2013-02-16 10:35:39

+0

@Guillaume欢迎您,很高兴为您效力:) – Lukazoid 2013-02-16 11:07:22

相关问题