WPF Multiple CollectionView 在同一集合上具有不同的过滤器
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16634194/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
WPF Multiple CollectionView with different filters on same collection
提问by drtf
I'm using a an ObservableCollectionwith two ICollectionViewfor different filters.
我正在为不同的过滤器使用ObservableCollection带有两个的 an ICollectionView。
One is for filtering messages by some type, and one is for counting checked messages. As you can see message filter and message count works OK, but when I'm un-checking the message disappear from the list (the count is still working).
一种用于按某种类型过滤消息,一种用于对检查的消息进行计数。如您所见,消息过滤器和消息计数工作正常,但是当我取消选中消息时,消息从列表中消失(计数仍在工作)。
BTW sorry for the long post, I wanted to include all relevant stuff.
顺便说一句,很抱歉这篇很长的帖子,我想包括所有相关的内容。
The XAML Code:
XAML 代码:
<!-- Messages List -->
<DockPanel Grid.Row="1"
Grid.Column="0"
Grid.ColumnSpan="3"
Height="500">
<ListBox Name="listBoxZone"
ItemsSource="{Binding filteredMessageList}"
Background="Transparent"
BorderThickness="0">
<ListBox.ItemTemplate>
<DataTemplate>
<CheckBox Name="CheckBoxZone"
Content="{Binding text}"
Tag="{Binding id}"
Unchecked="CheckBoxZone_Unchecked"
Foreground="WhiteSmoke"
Margin="0,5,0,0"
IsChecked="{Binding isChecked}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</DockPanel>
<Button Content="Test Add New"
Grid.Column="2"
Height="25"
HorizontalAlignment="Left"
Margin="34,2,0,0"
Click="button1_Click" />
<Label Content="{Binding checkedMessageList.Count}"
Grid.Column="2"
Height="25"
Margin="147,2,373,0"
Width="20"
Foreground="white" />
Screenshot:
截屏:
Code:
代码:
/* ViewModel Class */
public class MainViewModel : INotifyPropertyChanged
{
// Constructor
public MainViewModel()
{
#region filteredMessageList
// connect the ObservableCollection to CollectionView
_filteredMessageList = CollectionViewSource.GetDefaultView(messageList);
// set filter
_filteredMessageList.Filter = delegate(object item)
{
MessageClass temp = item as MessageClass;
if ( selectedFilter.Equals(AvailableFilters.All) )
{
return true;
}
else
{
return temp.filter.Equals(_selectedFilter);
}
};
#endregion
#region checkedMessageList
// connect the ObservableCollection to CollectionView
_checkedMessageList = CollectionViewSource.GetDefaultView(messageList);
// set filter
_checkedMessageList.Filter = delegate(object item) { return (item as MessageClass).isChecked; };
#endregion
}
// message List
private ObservableCollection<MessageClass> _messageList =
new ObservableCollection<MessageClass>();
public ObservableCollection<MessageClass> messageList
{
get { return _messageList; }
set { _messageList = value; }
}
// CollectionView (filtered messageList)
private ICollectionView _filteredMessageList;
public ICollectionView filteredMessageList
{
get { return _filteredMessageList; }
}
// CollectionView (filtered messageList)
private ICollectionView _checkedMessageList;
public ICollectionView checkedMessageList
{
get { return _checkedMessageList; }
}
// SelectedFilter property
private AvailableFilters _selectedFilter = AvailableFilters.All; // Default is set to all
public AvailableFilters selectedFilter
{
get { return _selectedFilter; }
set
{
_selectedFilter = value;
RaisePropertyChanged("selectedFilter");
_filteredMessageList.Refresh(); // refresh list upon update
}
}
// FilterList (Convert Enum To Collection)
private List<KeyValuePair<string, AvailableFilters>> _AvailableFiltersList;
public List<KeyValuePair<string, AvailableFilters>> AvailableFiltersList
{
get
{
/* Check if such list available, if not create for first use */
if (_AvailableFiltersList == null)
{
_AvailableFiltersList = new List<KeyValuePair<string, AvailableFilters>>();
foreach (AvailableFilters filter in Enum.GetValues(typeof(AvailableFilters)))
{
string Description;
FieldInfo fieldInfo = filter.GetType().GetField(filter.ToString());
DescriptionAttribute[] attributes =
(DescriptionAttribute[])fieldInfo.GetCustomAttributes(typeof(DescriptionAttribute), false);
/* if not null get description */
if (attributes != null && attributes.Length > 0)
{
Description = attributes[0].Description;
}
else
{
Description = string.Empty;
}
/* add as new item to filterList */
KeyValuePair<string, AvailableFilters> TypeKeyValue =
new KeyValuePair<string, AvailableFilters>(Description, filter);
_AvailableFiltersList.Add(TypeKeyValue);
}
}
return _AvailableFiltersList;
}
}
#region Implement INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
Code For un-check function
取消检查功能的代码
private void CheckBoxZone_Unchecked(object sender, RoutedEventArgs e)
{
CheckBox chkZone = (CheckBox)sender;
ucSystemMessageVM.checkedMessageList.Refresh();
}
回答by randcd
This answerhelped me with this exact problem. The static CollectionViewSource.GetDefaultView(coll)method will always return the same reference for a given collection, so basing multiple collection views on the same reference will be counterproductive. By instantiating the view as follows:
这个答案帮助我解决了这个确切的问题。CollectionViewSource.GetDefaultView(coll)对于给定的集合,静态方法将始终返回相同的引用,因此基于相同引用的多个集合视图将适得其反。通过如下实例化视图:
ICollectionView filteredView = new CollectionViewSource { Source=messageList }.View;
The view can now be filtered/sorted/grouped independently of any others. Then you can apply your filtering.
现在可以独立于任何其他视图过滤/排序/分组视图。然后你可以应用你的过滤。
I know it's been a couple months and you have probably solved your problem by now, but I ran across this question when I had the same problem so I figured I would add an answer.
我知道已经几个月了,你现在可能已经解决了你的问题,但是当我遇到同样的问题时我遇到了这个问题,所以我想我会添加一个答案。
回答by wulf11
For anyone struggling with the problem that the filteredView does not observe the sourceCollection (messageList in this example):
对于任何因filteredView没有观察到sourceCollection(在本例中为messageList)而苦苦挣扎的人:
I came around with this solution:
我想出了这个解决方案:
ICollectionView filteredView = new CollectionViewSource { Source=messageList }.View;
messageList.CollectionChanged += delegate { filteredView.Refresh(); };
So it will refresh our filteredView evertytime the CollectionChanged event of the source get's fired. Of course you can implement it like this too:
因此,它会在每次触发源 get 的 CollectionChanged 事件时刷新我们的 FilteredView。当然你也可以这样实现:
messageList.CollectionChanged += messageList_CollectionChanged;
private void messageList_CollectionChanged(object sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
filteredView.Refresh();
}
Consider using PropertyChanged-Events when filtering on a specific Property is wanted.
当需要过滤特定属性时,请考虑使用 PropertyChanged-Events。

