我有什么应用滤镜上的排序的ListCollectionView /的ObservableCollection
我已经做了TextBox
和ListBox
的UserControl
。 ListBox
的ItemsSource
通过ListCollectionView
通过ListCollectionView
绑定到ObservableCollection
的DataContext
,使用自定义排序和过滤器,我们将在下面看到。控制的目的是仅在ListBox
中显示源集合中包含TextBox
中文本的项目(string
)。为此,我在ListCollectionView
上应用了一个过滤器。
我有两个额外的限制。 1,我的原始集合未按字母顺序排序,但显示在ListBox
中的项目正在使用ListCollectionView
CustomSort
。 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
,而不是原来的非分类收集?
男人,你的解决方案是如此简单,但它工作得很好!已经3天了,我试图找出一个解决方案,不能接受任何东西......非常感谢! – Guillaume 2013-02-16 10:35:39
@Guillaume欢迎您,很高兴为您效力:) – Lukazoid 2013-02-16 11:07:22