mardi 12 janvier 2016

C# WPF: Bind/Apply filter with checkboxes created in runtime

I have a ListView with many MovieItems inside it. The ListView is bind to "FtMainList":

    ObservableCollection<MovieItem> MainList = new ObservableCollection<MoviItem>();
    public ICollectionView FtMainList
    {
        get
        {
            var source = CollectionViewSource.GetDefaultView(MainList);
            source.Filter = a => ListStatusFilter((MovieItem)a);
            return source;
        }
    }

A few days ago i created a filter for them:

Filter by status

        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");
    }

Those are Two-state CheckBoxes. So if i checked "Completed", the ListView will show all "completed movies". Otherwise, all completed movies will be hidden, and vice versa. It works as expected.

But, i dont want to stop there, i want to create more filter. Now i want to filter them by "Genre". The problem is, there are 26 genres (probably increasing), and i'm to lazy (lol) to create 26 checkboxes and their filters. So i have an idea:

    <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>

Code-behind:

            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;

Result:

Filter by genre

Unlike those above, these Checkboxes are 3-state. So if i checked "Action", the ListView will ONLY show movies which contains "Action" genre. If it is Null(a.k.a Intermediate), the ListView may show movie that doesn't contain "Action" genre. If it is Unchecked, all movies that doesn't contain "Action" genre will be hidden.

Now for the question, what should i do so these checkboxes will works as expected?




Aucun commentaire:

Enregistrer un commentaire