我有一个ListView
,里面有很多MovieItem
个。 ListView
绑定到“FtMainList”:
ObservableCollection<MovieItem> MainList = new ObservableCollection<MoviItem>();
public ICollectionView FtMainList
{
get
{
var source = CollectionViewSource.GetDefaultView(MainList);
source.Filter = a => ListStatusFilter((MovieItem)a);
return source;
}
}
几天前,我为他们创建了一个过滤器:
private bool ListStatusFilter(MovieItem movie)
{
return (LvFilter_Watching.IsChecked.HasValue && LvFilter_Watching.IsChecked.Value && movie.lMyStatus == "Watching") ||
(LvFilter_OnHold.IsChecked.HasValue && LvFilter_OnHold.IsChecked.Value && movie.lMyStatus == "On-Hold") ||
(LvFilter_PlanToWatch.IsChecked.HasValue && LvFilter_PlanToWatch.IsChecked.Value && movie.lMyStatus == "Plan To Watch") ||
(LvFilter_Dropped.IsChecked.HasValue && LvFilter_Dropped.IsChecked.Value && movie.lMyStatus == "Dropped") ||
(LvFilter_Completed.IsChecked.HasValue && LvFilter_Completed.IsChecked.Value && movie.lMyStatus == "Completed");
}
这些是双状态CheckBoxes。因此,如果我选中“已完成”,ListView
将显示所有“已完成的电影”。否则,所有已完成的电影都将被隐藏,反之亦然。它按预期工作。
但是,我不想停在那里,我想创建更多的过滤器。现在我想用“流派”过滤它们。问题是,有26种类型(可能正在增加),我要懒惰(lol)创建26个复选框及其过滤器。所以我有一个想法:
<DataTemplate x:Key="GenericList3StateCheckbox">
<CheckBox IsThreeState="True" Checked="FilterChanged" Unchecked="FilterChanged" Content="{Binding}" IsChecked="{x:Null}"/>
</DataTemplate>
...
<StackPanel Orientation="Vertical" Panel.ZIndex="1" Margin="0,0,0,10" HorizontalAlignment="Stretch">
<TextBlock Text="Genre" Margin="0,0,0,10" Panel.ZIndex="1" Foreground="White" FontSize="28" VerticalAlignment="Top" HorizontalAlignment="Center" FontFamily="Ebrima" TextDecorations="Underline" FontWeight="Bold"/>
<ListBox x:Name="LvFilter_Genres" HorizontalAlignment="Stretch" ScrollViewer.VerticalScrollBarVisibility="Visible" ItemTemplate="{StaticResource GenericList3StateCheckbox}" ScrollViewer.CanContentScroll="False" Height="130"/>
</StackPanel>
代码隐藏:
List<string> LvGenres = new List<string>();
foreach (MovieItem ame in MainList)
{
string[] spt = ame.gGenres.Split(new string[] { ", " }, StringSplitOptions.RemoveEmptyEntries);
foreach (string gen in spt)
{
bool isDuplicate = false;
foreach (string chk in LvGenres)
{
if (chk == gen)
{
isDuplicate = true;
break;
}
}
if (isDuplicate == false)
{
LvGenres.Add(gen);
}
}
}
LvGenres.Sort();
LvFilter_Genres.ItemsSource = LvGenres;
结果:
与上述不同,这些Checkbox是3状态。因此,如果我选中“动作”,ListView
将仅显示包含“动作”类型的电影。如果它是Null(a.k.a Intermediate),ListView
可能会显示不包含“Action”类型的电影。如果未选中,则将隐藏所有不包含“动作”类型的电影。
现在提出问题,我应该怎么做,这些复选框将按预期工作?
仅供参考,MovieItem
课程:
public class MovieItem : INotifyPropertyChanged
{
public string Title { get; set; }
public string Genres { get; set; }
public int Duration { get; set; }
public string lMyStatus { get; set; }
public event PropertyChangedEventHandler PropertyChanged;
}
Genres
是一个单独的字符串,包含一些用昏迷和空格分隔的“流派”。例如:“动作,惊悚片,文件管理员”
答案 0 :(得分:2)
最好使用ListBox项的自定义View Model而不是字符串。在这种情况下,您可以更灵活地实现您想要的任何内容。
<DataTemplate x:Key="GenericList3StateCheckbox">
<CheckBox IsThreeState="True" Checked="FilterChanged" Unchecked="FilterChanged" Content="{Binding Caption}" IsChecked="{Binding State}"/>
</DataTemplate>
List<FilterItemVM> LvGenres = new List<FilterItemVM>();
public class FilterItemVM : INotifyPropertyChanged
{
private string _caption;
public string Caption
{
get { return _caption; }
set
{
_caption= value;
OnPropertyChanged();
}
}
private bool? _state;
public bool? State
{
get { return _state; }
set
{
_state= value;
OnPropertyChanged();
}
}
protected void OnPropertyChanged([CallerMemberName] string property = null)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(property));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
private bool ListStatusFilter(MovieItem movie)
{
List<string> itemGengres = movie.Genres.Split(',').Select(g => g.Trim()).ToList();
List<string> obligatoryGengres = LvGenres.Where(fi => fi.State.HasValue && fi.State.Value == true).Select(fi => fi.Caption).ToList();
List<string> forbiddenGengres = LvGenres.Where(fi => fi.State.HasValue && fi.State.Value == false).Select(fi => fi.Caption).ToList();
bool isGenresMatched = obligatoryGengres.All(g => itemGengres.Contains(g)) && !forbiddenGengres.Any(g => itemGengres.Contains(g));
return isGenresMatched && (LvFilter_Watching.IsChecked.HasValue && LvFilter_Watching.IsChecked.Value && movie.lMyStatus == "Watching") ||
(LvFilter_OnHold.IsChecked.HasValue && LvFilter_OnHold.IsChecked.Value && movie.lMyStatus == "On-Hold") ||
(LvFilter_PlanToWatch.IsChecked.HasValue && LvFilter_PlanToWatch.IsChecked.Value && movie.lMyStatus == "Plan To Watch") ||
(LvFilter_Dropped.IsChecked.HasValue && LvFilter_Dropped.IsChecked.Value && movie.lMyStatus == "Dropped") ||
(LvFilter_Completed.IsChecked.HasValue && LvFilter_Completed.IsChecked.Value && movie.lMyStatus == "Completed");
}