1

在过去的几天里,我遇到了一个问题,导致我的头撞在桌子上。

本质上,我要做的是生成两个单独的复选框列表,这些复选框对应于类的两个属性(制造商和类别),并根据用户检查的内容过滤它们。

我所做的是创建两个对应于每个属性的高级集合视图,并用它们各自的对象填充它们。我创建了过滤器来根据用户的选择过滤每个视图,但无论我做什么,行为都与我无法确定将问题追溯到哪里的地方不一致。

应该发生的情况是,如果用户选择制造商,则类别列表应过滤掉不包括所选制造商的类别,反之亦然。到目前为止,唯一能以这种方式工作的复选框是为附件类别生成的复选框。

下面是我看到的行为的视频。在视频的第一部分,您可以看到使用附件类别和 Microsoft 制造商时它应该如何工作,但随着视频的进行,我尝试不同的组合,您可以看到其余选项的奇怪但随机的行为。

https://youtu.be/atnmh5PdFeM

我只是想不通的是为什么它可以完美地工作,并且正如我打算针对一个类别/制造商而不是其他任何一个类别/制造商一样。UI 都是动态生成的,填充列表的对象都是相同的类型,数据都是相同的格式,所有的列表都会正确生成。我真的很茫然,我真的希望有一些外界的看法!

以下是一些相关代码:

XAML:

<Grid Background="#FF1B1B1B">
    <StackPanel Orientation="Horizontal">
        <StackPanel HorizontalAlignment="Left" Width="470">
            <TextBlock Text="Product Catalog" FontSize="28" Foreground="#FFCDCDCD" Margin="5"/>
            <Button x:Name="AddCustomerButton"  HorizontalAlignment="Stretch" Content="Clear All Filters" VerticalAlignment="Stretch" Height="60" Background="#FF007ACC" Margin="15" Foreground="#FFCDCDCD" />
            <ScrollViewer  Margin="5,5,0,5" Height="115" BorderThickness="3" BorderBrush="#FF575454">
                <StackPanel Height="146" Width="435">
                    <TextBlock Text="Category:" Foreground="#FFCDCDCD"/>
                    <ListView x:Name="CategoryList" ItemsSource="{Binding CategoryCheckboxes}" >
                        <ListView.ItemsPanel >
                            <ItemsPanelTemplate >
                                <ItemsWrapGrid Orientation="Horizontal" Width="435"  />
                            </ItemsPanelTemplate>
                        </ListView.ItemsPanel>
                        <ListView.ItemTemplate>
                            <DataTemplate >
                                <CheckBox Foreground="#FFCDCDCD" IsChecked="{Binding IsCheckedCategory, Mode=TwoWay}"  >
                                    <interactivity:Interaction.Behaviors>
                                        <core:EventTriggerBehavior EventName="Checked">
                                            <core:InvokeCommandAction CommandParameter="{Binding}" Command="{Binding ElementName=CategoryList,  Path=DataContext.CheckCategory}" />
                                        </core:EventTriggerBehavior>
                                        <core:EventTriggerBehavior EventName="Unchecked">
                                            <core:InvokeCommandAction CommandParameter="{Binding}" Command="{Binding ElementName=CategoryList,  Path=DataContext.UncheckCategory}" />
                                        </core:EventTriggerBehavior>
                                    </interactivity:Interaction.Behaviors>
                                    <TextBlock Text="{Binding Category}"  Foreground="#FFCDCDCD"/>
                                </CheckBox>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </StackPanel>
            </ScrollViewer>

            <ScrollViewer Margin="5,5,0,5" Height="200" BorderThickness="3" BorderBrush="#FF575454">
                <StackPanel>
                    <TextBlock Text="Manufacturer:" Foreground="#FFCDCDCD"/>
                    <ListView x:Name="ManufacturerList" ItemsSource="{Binding ManufacturerCheckboxes}">
                        <ListView.ItemsPanel>
                            <ItemsPanelTemplate>
                                <ItemsWrapGrid Orientation="Horizontal"  Width="435" />
                            </ItemsPanelTemplate>
                        </ListView.ItemsPanel>
                        <ListView.ItemTemplate>
                            <DataTemplate >
                                <CheckBox Foreground="#FFCDCDCD" IsChecked="{Binding IsCheckedMfg, Mode=TwoWay}">
                                    <interactivity:Interaction.Behaviors>
                                        <core:EventTriggerBehavior EventName="Checked">
                                            <core:InvokeCommandAction CommandParameter="{Binding}" Command="{Binding ElementName=ManufacturerList,  Path=DataContext.CheckManufacterer}" />
                                        </core:EventTriggerBehavior>
                                        <core:EventTriggerBehavior EventName="Unchecked">
                                            <core:InvokeCommandAction CommandParameter="{Binding}" Command="{Binding ElementName=ManufacturerList,  Path=DataContext.UncheckManufacterer}" />
                                        </core:EventTriggerBehavior>
                                    </interactivity:Interaction.Behaviors>
                                    <TextBlock Text="{Binding Manufacturer}"  Foreground="#FFCDCDCD"/>
                                </CheckBox>
                            </DataTemplate>
                        </ListView.ItemTemplate>
                    </ListView>
                </StackPanel>
            </ScrollViewer>
        </StackPanel>
        <StackPanel Margin="3">
            <TextBlock Text="Products" FontSize="28" Foreground="#FFCDCDCD" Margin="5"/>
            <StackPanel Orientation="Horizontal" Margin="5">
                <TextBlock Text="Search: " FontSize="24" Foreground="#FFCDCDCD" Width="86" Margin="3"/>
                <TextBox x:Name="SearchTextBoxt" TextChanged="SearchTextBoxt_TextChanged" Width="725" Margin="3" TextChanging="SearchTextBoxt_TextChanging"/>
            </StackPanel>
        <ListView ItemsSource="{x:Bind pcvm.ProductCatalog}"  Width="837" Margin="5" Height="728">
            <ListView.ItemTemplate>
                <DataTemplate x:DataType="models:Product">
                    <controls:Expander x:Name="Expander1" VerticalAlignment="Top" Margin="0,0,0,10"
                                       BorderBrush="Bisque"
                                       Header="{Binding Name}"
                                       IsExpanded="False" Width="810" Foreground="#FFCDCDCD">
                        <Grid Height="auto" Background="#FF272727" Width="805" BorderThickness="3" BorderBrush="DimGray">
                            <StackPanel Orientation="Horizontal" Height="auto">
                                <StackPanel Width="275" Height="auto">
                                    <TextBlock Text="{Binding Manufacturer}" Foreground="#FFCDCDCD" FontSize="24" Height="auto" Margin="3"/>
                                    <Image Source="{Binding ImageUrl}" Margin="3" Height="151"/>
                                    <TextBlock Text="{Binding Price}" Foreground="#FFCDCDCD" FontSize="24" Height="auto" Margin="3" FlowDirection="RightToLeft"/>
                                </StackPanel>
                                <StackPanel Width="522">
                                    <TextBlock Text="{Binding Name}" Foreground="#FFCDCDCD" FontSize="18" FontWeight="Bold" Height="auto" Margin="2"/>
                                    <TextBlock Text="{Binding Description}" Foreground="#FFCDCDCD" FontSize="16" Height="auto" Margin="3" TextWrapping="Wrap"/>
                                    <TextBlock Text="{Binding Processor}" Foreground="#FFCDCDCD" FontSize="14" FontStyle="Italic" Height="auto" Margin="5,8,5,5"/>
                                    <TextBlock Text="{Binding RAM}" Foreground="#FFCDCDCD" FontSize="14" FontStyle="Italic" Height="auto" Margin="5"/>
                                    <TextBlock Text="{Binding HDDCap}" Foreground="#FFCDCDCD" FontSize="14" FontStyle="Italic" Height="auto" Margin="5"/>
                                    <TextBlock Text="{Binding GPU}" Foreground="#FFCDCDCD" FontSize="14" FontStyle="Italic" Height="auto" Margin="5"/>
                                    <TextBlock Text="{Binding Display}" Foreground="#FFCDCDCD" FontSize="14" FontStyle="Italic" Height="auto" Margin="5"/>
                                </StackPanel>
                            </StackPanel>
                        </Grid>
                    </controls:Expander>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>
        </StackPanel>
    </StackPanel>
</Grid>`

C#虚拟机:

public class ProductCatalogViewModel 
{
    public enum FilterTypes
    {
        Category, Manufacterer
    }
    public AdvancedCollectionView ProductCatalog { get; set; }
    public List<Product> Products { get; set; }

    public AdvancedCollectionView ManufacturerCheckboxes { get; set; }
    public AdvancedCollectionView CategoryCheckboxes { get; set; }
    public AdvancedCollectionView CheckBoxesCollectionView { get; set; }

    private List<string> _searchFilters;
    private string searchParam = "";
    private bool _mfgSeclected, _categorySelected, _subCategorySelected = false;
    private string _mfgFilter, _categoryFilter, _subCategoryFilter;
    public ProductCatalogProduct selectedMfgCheckbox { get; set; }
    public ProductCatalogProduct selectedCatCheckbox { get; set; }


    public ICommand CheckCategory { get; set; }
    public ICommand UncheckCategory { get; set; }
    public ICommand CheckManufacterer { get; set; }
    public ICommand UncheckManufacterer { get; set; }


    public ProductCatalogViewModel()
    {
        Products = (DataManager._productDatabase);
        ProductCatalog = new AdvancedCollectionView(Products);
        GenerateCheckBoxLists();
        CheckCategory = new RelayCommand<ProductCatalogProduct>(CheckCategoryFilter);
        UncheckCategory = new RelayCommand<ProductCatalogProduct>(UncheckCategoryFilter);
        CheckManufacterer = new RelayCommand<ProductCatalogProduct>(CheckManufacturerFilter);
        UncheckManufacterer = new RelayCommand<ProductCatalogProduct>(UncheckManufacturerFilter);

    }

    private void GenerateCheckBoxLists() //Generates the object collections that will represent the filter checkboxes in the View
    {
        ManufacturerCheckboxes = new AdvancedCollectionView(new ObservableCollection<ProductCatalogProduct>());
        ManufacturerCheckboxes = GenerateDistinctList(ProductCatalog, ProductComparer.ListTypes.Manufacturer);

        foreach (ProductCatalogProduct mfgCheckBoxItem in ManufacturerCheckboxes)
        {
            foreach (Product product in Products)
            {
                if (mfgCheckBoxItem.Manufacturer == product.Manufacturer && !mfgCheckBoxItem.CategoriesWithSameManufacterer.Contains(product.Category) )
                {
                    mfgCheckBoxItem.CategoriesWithSameManufacterer.Add(product.Category);
                }
            }
        }

        CategoryCheckboxes = new AdvancedCollectionView(new ObservableCollection<ProductCatalogProduct>());
        CategoryCheckboxes = GenerateDistinctList(ProductCatalog, ProductComparer.ListTypes.Category);

        foreach (ProductCatalogProduct catCheckBoxItem in CategoryCheckboxes)
        {
            foreach (Product product in Products)
            {
                if (catCheckBoxItem.Category == product.Category && !catCheckBoxItem.ManufacturersWithSameCategory.Contains(product.Manufacturer))
                {
                    catCheckBoxItem.ManufacturersWithSameCategory.Add(product.Manufacturer);
                }
            }
        }

    }

    private AdvancedCollectionView GenerateDistinctList(AdvancedCollectionView viewToFilter, ProductComparer.ListTypes list)
    {

                AdvancedCollectionView newACV = new AdvancedCollectionView(new ObservableCollection<ProductCatalogProduct>());
                List<Product> tempList = new List<Product>();
        foreach (Product pcp in viewToFilter)
        {
            tempList.Add(pcp);
        }
                IEnumerable<Product> NoDuplicatesInitialCat = tempList.Distinct(new ProductComparer(list));
                foreach (var p in NoDuplicatesInitialCat)
                {
            ProductCatalogProduct pCP = new ProductCatalogProduct(p);
                    newACV.Add(pCP);
                }

        return newACV;


    }

    private void UncheckAllCategories()
    {
        CategoryCheckboxes.ToList().ForEach(x =>
        {
 (x as ProductCatalogProduct).UncheckCategory();

        });
    }
    private void UncheckAllManufacterers()
    {
        ManufacturerCheckboxes.ToList().ForEach(x =>
        {

                (x as ProductCatalogProduct).UncheckMfg();

        });
    }


    public void CheckCategoryFilter(ProductCatalogProduct product)
    {
        if (selectedCatCheckbox != null)
        {
            selectedCatCheckbox.UncheckCategory();
            selectedCatCheckbox = null;
        }
        _categoryFilter = product.Category;
        FilterButtons(FilterTypes.Category);
        UncheckAllCategories();
        selectedCatCheckbox = product;
        if (selectedMfgCheckbox != null)
        {
            selectedMfgCheckbox.CheckMfg();
        }
        selectedCatCheckbox.CheckCategory();
       // ExecuteProductFilter();          
    }

    public void UncheckCategoryFilter(ProductCatalogProduct product)
    {
        if (selectedCatCheckbox != null)
        {
            selectedCatCheckbox.UncheckCategory();
            selectedCatCheckbox = null;
        }
        _categorySelected = false;
        _categoryFilter = String.Empty;
        ManufacturerCheckboxes.Filter = null;
        if (selectedMfgCheckbox != null)
        {

            selectedMfgCheckbox.CheckMfg();
        }
       // ExecuteProductFilter();
    }

    public void CheckManufacturerFilter(ProductCatalogProduct product)
    {
        if (selectedMfgCheckbox != null)
        {
            selectedMfgCheckbox.UncheckCategory();
            selectedMfgCheckbox = null;
        }
        _mfgFilter = product.Manufacturer;
        FilterButtons(FilterTypes.Manufacterer);
        UncheckAllManufacterers();
        selectedMfgCheckbox = product;
        if (selectedCatCheckbox != null)
        {
            selectedCatCheckbox.CheckMfg();
        }
        selectedMfgCheckbox.CheckMfg();
        //ExecuteProductFilter();
    }

    public void UncheckManufacturerFilter(ProductCatalogProduct product)
    {
        if (selectedMfgCheckbox != null)
        {
            selectedMfgCheckbox.UncheckCategory();
            selectedMfgCheckbox = null;
        }
        _mfgSeclected = false;
        _mfgFilter = String.Empty;
        CategoryCheckboxes.Filter = null;
        if (selectedCatCheckbox != null)
        {
            selectedCatCheckbox.CheckMfg();
        }
        //ExecuteProductFilter();
    }



    private List<Predicate<Product>> _criteria = new List<Predicate<Product>>();




    private bool dynamic_Filter(object item)
    {
        Product p = item as Product;
        bool isIn = true;
        if (_criteria.Count() == 0)
            return isIn;
        isIn = _criteria.TrueForAll(x => x(p));

        return isIn;
    }


    private void FilterButtons(FilterTypes filterSelected)
    {

        switch (filterSelected)
        {
            case FilterTypes.Category:

                ManufacturerCheckboxes.Filter = null;
                ManufacturerCheckboxes.Filter = x => (x as ProductCatalogProduct).CategoriesWithSameManufacterer.Contains(_categoryFilter);
                break;
            case FilterTypes.Manufacterer:
                CategoryCheckboxes.Filter = null;
                CategoryCheckboxes.Filter = x => (x as ProductCatalogProduct).ManufacturersWithSameCategory.Contains(_mfgFilter);
                break;
        }



    }




    private void ExecuteProductFilter()
    {

        ProductCatalog.Filter = null;

        _criteria.Clear();

        if (_categorySelected)
        {
            _criteria.Add(new Predicate<Product>(x => x.Category.Contains(_categoryFilter)));
        }
        if (_subCategorySelected)
        {
            _criteria.Add(new Predicate<Product>(x => x.SubCategory.Contains(_subCategoryFilter)));
        }
        if (_mfgSeclected)
        {
            _criteria.Add(new Predicate<Product>(x => x.Manufacturer.Contains(_mfgFilter)));
        }

        ProductCatalog.Filter = dynamic_Filter;
    }



    public void FilterProductDatabase(string searchParameters) //filters the advancedcollectionview using the SearchFilter method
    {
        searchParam = searchParameters;
        ProductCatalog.Filter = SearchFilter;
    }

    private bool SearchFilter(object item) //Filters each object in the advancedcollectionview based on user input into a textbox
    {


        Product p = item as Product;
        string searchTerms = "";
        searchTerms = p.Manufacturer + " " + p.Category + " " + p.SubCategory;
        if (searchTerms.Contains(searchParam))
        {
            return true;
        }
        else
        {
            return false;
        }
    }


    class ProductComparer : IEqualityComparer<Product>
    {
        public enum ListTypes
        {
            Manufacturer, Category, Subcategory
        }

        public ListTypes lists;

        public ProductComparer(ListTypes listToFill)
        {

            lists = listToFill;

        }

        // Products are equal if their names and product numbers are equal.
        public bool Equals(Product x, Product y)
        {

            switch (lists)
            {
                case ListTypes.Category:
                    if (Object.ReferenceEquals(x, y)) return true;
                    if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y.Manufacturer, null))
                        return false;
                    return x.Category == y.Category;

                case ListTypes.Manufacturer:
                    if (Object.ReferenceEquals(x, y)) return true;
                    if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y.Manufacturer, null))
                        return false;
                    return x.Manufacturer == y.Manufacturer;

                case ListTypes.Subcategory:
                    if (Object.ReferenceEquals(x, y)) return true;
                    if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y.Manufacturer, null))
                        return false;
                    return x.SubCategory == y.SubCategory;
            }
            return false;
        }

        // If Equals() returns true for a pair of objects 
        // then GetHashCode() must return the same value for these objects.

        public int GetHashCode(Product product)
        {
            switch (lists)
            {
                case ListTypes.Category:
                    if (Object.ReferenceEquals(product, null)) return 0;
                    int hashProductCategory = product.Category == null ? 0 : product.Category.GetHashCode();
                    return hashProductCategory;

                case ListTypes.Manufacturer:
                    if (Object.ReferenceEquals(product, null)) return 0;
                    int hashProductManufacturer = product.Manufacturer == null ? 0 : product.Manufacturer.GetHashCode();
                    return hashProductManufacturer;

                case ListTypes.Subcategory:
                    //Check whether the object is null
                    if (Object.ReferenceEquals(product, null)) return 0;

                    //Get hash code for the Name field if it is not null.
                    int hashProductSubCategory = product.SubCategory == null ? 0 : product.SubCategory.GetHashCode();

                    //Calculate the hash code for the product.
                    return hashProductSubCategory;

            }
            return 0;
        }


    }
}`

数据模型:

public  class ProductCatalogProduct : Product, INotifyPropertyChanged
 {
    private bool _isCheckedCategory;
    public bool IsCheckedCategory
    {
        get { return _isCheckedCategory; }
        set { _isCheckedCategory = value; NotifyPropertyChanged("IsCheckedCategory"); }
    }

    private bool _isCheckedMfg;
    public bool IsCheckedMfg
    {
        get { return _isCheckedMfg; }
        set { _isCheckedMfg = value; NotifyPropertyChanged("IsCheckedMfg"); }
    }
    public ProductCatalogProduct(Product productBase)
    {
        Manufacturer = productBase.Manufacturer;
        Category = productBase.Category;
        Price = productBase.Price;
        ManufacturersWithSameCategory = new List<string>();
        CategoriesWithSameManufacterer = new List<string>();
    }

    public event PropertyChangedEventHandler PropertyChanged;
    public void NotifyPropertyChanged(String propertyName)
    {
        PropertyChangedEventHandler handler = PropertyChanged;
        if (null != handler)
        {
            handler(this, new PropertyChangedEventArgs(propertyName));
        }
    }

    public List<string> ManufacturersWithSameCategory { get; set; }
    public List<string> CategoriesWithSameManufacterer { get; set; }

    public void UncheckAll()
    {
        IsCheckedCategory = false;
        IsCheckedMfg = false;
    }

    public void CheckAll()
    {
        IsCheckedCategory = true;
        IsCheckedMfg = true;
    }

    public void CheckCategory()
    {
        IsCheckedCategory = true;
    }

    public void UncheckCategory()
    {
        IsCheckedCategory = false;
    }

    public void CheckMfg()
    {
        IsCheckedMfg = true;
    }

    public void UncheckMfg()
    {
        IsCheckedMfg = false;
    }

    public bool GetCategoryChecked()
    {
        return IsCheckedCategory;
    }

    public bool GetMfgChecked()
    {
        return IsCheckedMfg;
    }
}`
4

0 回答 0