WPF多重筛选CollectionViewSource,第一个添加的筛选器正常工作,第二个添加的筛选器不起作用。

3
我有一个ListView,它绑定到一个CollectionViewSource。我按照这篇文章(被许多人引用)进行了多重过滤:http://www.zagstudio.com/blog/456#.UG8r6E1lWLE 我设置了两个复选框进行测试,仅添加过滤器。每当我首先点击其中一个时,过滤器就会添加到CollectionViewSource并且可以使用。然后,当我点击另一个复选框时,我的listview变空了(根据数据不应该如此,而且无论以哪种顺序勾选复选框都会发生这种情况)。
以下是相关代码:(背景:此应用程序处理运输软件的“订单”过滤)
加载订单:
public class Order
{
    public int index { get; set; }
    public string host { get; set; }
    public Int64 orderNumber { get; set; }
    public string batchStatus { get; set; }
    public string sku { get; set; }
    public int numItems { get; set; }
    public string orderSource { get; set; }
    public string sourceOrderNumber { get; set; }
    public DateTime orderDate { get; set; }
    public DateTime orderTime { get; set; }
    public int customerID { get; set; }
    public string shipMethod { get; set; }
    public string billingState { get; set; }
    public bool statusChanged { get; set; }
    public int numSkus { get; set; }
    public string marketName { get; set; }
    public float weight { get; set; }
}

public class Orders : ObservableCollection<Order>
{
    public Orders()
    {
        SqlDataReader reader1 = cmd.ExecuteReader();
        while (reader1.Read())
        {
            Order order = new Order();

            order.host = (string)safeGetString(reader1, 0);
            order.orderNumber = (Int64)reader1["OrderNumber"];
            order.batchStatus = (string)safeGetString(reader1, 2);
            order.orderSource = (string)safeGetString(reader1, 3);
            order.sourceOrderNumber = safeGetString(reader1, 4);
            order.orderDate = (DateTime)reader1["OrderDate"];
            order.customerID = (int)reader1["CustomerID"];
            order.shipMethod = (string)safeGetString(reader1, 7);
            order.billingState = (string)safeGetString(reader1, 8);
            order.numItems = (int)reader1["NumItems"];
            order.numSkus = (int)reader1["NumSKUs"];
            order.marketName = (string)safeGetString(reader1, 11);
            order.weight = (float)(double)reader1["ShippedWeight"];


            this.Add(order);
        }
        reader1.Close();
    }

设置CollectionViewSource:

cvs = (CollectionViewSource)(this.Resources["cvs"]);

复选框功能:(使用 filterString 进行测试时硬编码“按什么进行过滤”)

public void checkBox2_Checked(object sender, RoutedEventArgs e)
    {
        filterString = "TX";
        cvs.Filter += new FilterEventHandler(billingStateFilter);
    }
    public void checkBox1_Checked(object sender, RoutedEventArgs e)
    {
        filterString = "Standard";
        cvs.Filter += new FilterEventHandler(shippingMethodFilter);
    }

最后是过滤器:
private void shippingMethodFilter(object sender, FilterEventArgs e)
    {
        Order order = e.Item as Order;
        if ((order.shipMethod != filterString))
        {
            e.Accepted = false;
        }
    }

    public void billingStateFilter(object sender, FilterEventArgs e)
    {
        Order order = e.Item as Order;
        if ((order.billingState != filterString))
        {
            e.Accepted = false;
        }
    }

就像我说的一样,第一个过滤器总是有效的。第二个过滤器总是使屏幕变空白。有什么想法吗?


那么您肯定有既是TX又是标准的记录?在调试中处理程序被调用了吗? - paparazzo
3个回答

1

您正在同时重复使用筛选字符串来进行两个筛选,一旦您勾选每个框,两个筛选都将被应用。所以如果您:

  1. 勾选checkBox1,那么filterString将是“Standard”,并且shippingMethodFilter将被连接。
  2. 勾选checkBox2,那么filterString将是“TX”,并且billingStateFilter将被连接。

在任何时候,shippingMethodFilter都不会被取消连接。因此,它将继续根据filterString为“TX”进行筛选。

您应该添加一个筛选方法,检查是否已勾选checkBox1/checkBox2,然后选择性地应用其筛选逻辑。例如:

private string shippingFilterString = "Shipping";
private string billingFilterString = "TX";

private void collFilter(object sender, FilterEventArgs e)
{
    Order order = e.Item as Order;
    if (checkBox1.IsChecked == true && (order.shipMethod != shippingFilterString ))
        e.Accepted = false;
    if (checkBox2.IsChecked == true && (order.billingState != billingFilterString ))
        e.Accepted = false;
}

如果我有多个复选框过滤器,这些过滤器是根据从数据库检索到的数据动态创建的,那么创建这些“过滤器字符串”的理想方法是什么,以便可以应用多个过滤器而不会互相干扰? - Kevin Quiring
@user1667022 - 这取决于您的需求。您可以构建一个 Func<Order,bool> 委托列表。或者只是拥有一个字符串列表以及它们所关联的属性。很难说哪种方法是最好的 :-) - CodeNaked
我认为你是对的,但我不知道该选择哪个,让我向您展示一个过滤器...(见下面代码) - Kevin Quiring

1
我已经发布了一篇博客:https://hoomanvisualstudio.blogspot.com/b/post-preview?token=mpPyAk0BAAA.ygnewdzslszANX8AchX0hg.uW17QZR22-f_JUqjDTBcyA&postId=4200491240358821673&type=POST 有很多方法,其中一种简单的方法是将您的条件合并为一个谓词。
我的视图模型是MyViewModel。
//将您的过滤器放入集合中 var _itemSourceList = myViewModel.MyCollection;
var filter = new Predicate(item => ((Model)item).FirstName.ToString().Contains("John") && ((Model)item).LastName.ToString().Contains("Doe"));
_itemSourceList.Filter = filter; myDataGrid.ItemsSource = myViewModel.MyCollection;

0
for (i = 0; i < numberItemsFilterStrings.Length; i++)
            {
                switch (numberItemsFilterStrings[i])
                {
                    case "One Item":
                        if (order.numItems != 1)
                        {
                            e.Accepted = false;
                        }
                        break;
                    case "Between 2 - 5":
                        if ((order.numItems < 2) || (order.numItems > 5))
                        {
                            e.Accepted = false;
                        }
                        break;
                    case "Between 6 - 25":
                        if ((order.numItems < 6) || (order.numItems > 24))
                        {
                            e.Accepted = false;
                        }
                        break;
                    case "Greater Than 25":
                        if (order.numItems < 25)
                        {
                            e.Accepted = false;
                        }
                        break;
                }
            }

这是我正在创建的一个过滤器的代码。它适用于第一个过滤器,因为所有不符合过滤条件的订单都不被接受。但是当我勾选第二个过滤器框时,没有任何订单显示出来,因为最初被接受的订单中有些现在也不符合条件,导致没有订单被显示。


不同的过滤器字符串现在存储在该数组numberItemsFilterStrings中。 - Kevin Quiring

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接