【问题标题】:WPF multiple filters CollectionViewSource, first filter added works correctly, second filter added does notWPF 多个过滤器 CollectionViewSource,添加的第一个过滤器可以正常工作,添加的第二个过滤器不能
【发布时间】:2012-10-05 19:09:51
【问题描述】:

我有一个绑定到 CollectionViewSource 的 ListView。我按照这篇文章(被很多人引用)进行了多重过滤:http://www.zagstudio.com/blog/456#.UG8r6E1lWLE

我设置了两个用于测试的复选框,除了添加一个过滤器之外什么都不做。每当我首先单击其中一个时,过滤器都会添加到 CollectionViewSource 并且它可以工作。然后,当我单击相反的复选框时,而不是将另一个过滤器添加到 CollectionViewSource 并且两个过滤器都在工作,我的列表视图变为空白(当它不应该基于数据时,这会以选中我的复选框的顺序发生)

以下是相关代码:(背景:此应用程序用于过滤运输软件的“订单”)

加载订单:

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和标准的记录吗?在调试中是否调用了处理程序?

标签: wpf filter event-handling collectionviewsource


【解决方案1】:

您正在为两个过滤器重复使用过滤器字符串,并且一旦您选中每个框两个过滤器将被应用。所以如果你:

  1. 选中 checkBox1,然后 filterString 将为“标准”,并连接 shippingMethodFilter。
  2. 勾选 checkBox2,filterString 将为“TX”,billingStateFilter 将被连接。

shippingMethodFilter 绝不会脱钩。所以它将继续基于“TX”的filterString进行过滤。

您可能应该添加一个过滤器方法来检查是否检查了 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;
}

【讨论】:

  • 因此,如果我有多个根据从数据库检索到的数据动态创建的复选框过滤器,那么创建这些“过滤器字符串”的理想方法是什么,以便可以应用多个过滤器而不会干扰彼此?
  • @user1667022 - 这真的取决于您的需求。你可以建立一个Func&lt;Order,bool&gt; 代表的列表。或者只是有一个字符串列表以及它们关联的属性。很难说最好的方法是什么:-)
  • 我认为您是对的,但我不知道该选择哪一个,所以让我向您展示其中一个过滤器...(下面的代码)
【解决方案2】:

我已经为此发表了一篇博客:https://hoomanvisualstudio.blogspot.com/b/post-preview?token=mpPyAk0BAAA.ygnewdzslszANX8AchX0hg.uW17QZR22-f_JUqjDTBcyA&postId=4200491240358821673&type=POST

有很多方法。一种简单的方法是将条件滚动到一个谓词中。

MyViewModel myViewModel = new MyViewModel();

// 将采用您的过滤器的集合 var _itemSourceList = myViewModel.MyCollection;

var filter = new Predicate(item => ((Model)item).FirstName.ToString().Contains("John") && ((Model)item).LastName.ToString().Contains("Doe" ));

_itemSourceList.Filter = 过滤器; myDataGrid.ItemsSource = myViewModel.MyCollection;

【讨论】:

    【解决方案3】:
    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
    猜你喜欢
    • 2015-07-03
    • 1970-01-01
    • 1970-01-01
    • 2018-11-26
    • 1970-01-01
    • 2020-10-07
    • 1970-01-01
    • 2023-02-20
    • 2015-05-09
    相关资源
    最近更新 更多