根据单元格值过滤datagridview中的对象列表

时间:2018-05-22 17:50:17

标签: c# .net winforms linq reflection

我目前不确定如何在数据网格中将数据源设置为对象列表的最佳方法。

因此,我们的目标是:

    public class DepositAccountBill
    {
        #region Properties
        public int AccountBillID { get; set; }
        public int AccountID { get; set; }
        public string AccountNumber { get; set; }
        public string ControlNumber { get; set; }
        public DateTime BillDate { get; set; }
        public decimal DepositAmount { get; set; }
}

我有一个大致如下的datagridview表:

Account Number  |  Control Number  | Bill Date  |   Deposit Amount 
==================================================================
123456          | AJA1234367       | 5/21/2018  | 12.99 
123456          | PSA1234367       | 5/21/2018  | 5.77 
567332          | HBA1234367       | 5/21/2018  | 1255.99 
769843          | AJA1234367       | 5/21/2018  | 12.99 

所以当点击一个单元格时。让我们说第一列的第一个单元格。如果我右键单击一个单元格并在上下文菜单中选择一个选项,该选项显示过滤器我需要显示datagridview表,其中只有具有相同帐号的行。在这种情况下,它将是第1行和第2行。 为了让我这样做,我必须访问使用DepositAccountBill填充datagridview表的对象。所以我需要做的就是看一下我所看到的专栏中有选定单元格的值。

所以在我的方法中,到目前为止我没有尝试过任何结果:

var collection = (List<DepositAccountBill>)dataGridView1.DataSource;
var filterList = collection.Where ( q => (collection.Select(r => GetPropValue(r, dataGridView1.Columns[clickedCell.ColumnIndex].DataPropertyName))) == (clickedCell.Value);

dataGridView1.DataSource = filterList.ToList();

public object GetPropValue(object obj, string propName)
{
    return obj.GetType().GetProperty(propName).GetValue(obj, null);
}

我不知道SELECT是否是在这里使用的正确LINQ方法,或者甚至可能。 我想使用WHERE,因为它只抓取符合条件的对象列表。像这样:

var filterList = collection.Where(r => r.AccountNumber == clickedCell.Value); 

唯一的问题是r.AccountNumber依赖于所选列的数据属性。程序不知道基于所选单元格上的单击事件的数据属性是什么。这就是我认为可能需要反思的原因。

1 个答案:

答案 0 :(得分:3)

我想您知道如何使用列的DataPropertyName属性提取属性名称,以及如何从单元格的Value属性中获取值。

在答案中,我将重点介绍如何动态过滤具有属性名称 List<T> ,就像你使用.Where(x=>x.PropertyName == Value)时一样。

为此,您可以选择几个选项,包括:

  1. 动态Linq图书馆
  2. 在运行时动态创建Expression
  3. 使用每个属性所需的Dictionary条件
  4. 只需使用if / else
  5. 我将分享有关上述解决方案的更多详细信息,您可以选择其中任何一种。

    注意: 如果答案太长,可能最简单,最明显的答案就是第4个选项。

    选项1 - 动态Linq库

    作为一个选项,您可以向项目添加System.Linq.Dynamic引用,然后在使用System.Linq.Dynamic命名空间后,您就可以在IEnumerable<T>IQueryable<T>上创建动态查询了将标准传递为string,例如:

    var list = db.Products.ToList();
    var result = list.Where("Name = @0", "product1").ToList();
    

    这样,您可以简单地动态地使用查询中的列数据属性名称和列值。要查找有关动态linq的更多信息,请查看以下资源:

    • NuGet package代表System.Linq.Dynamic。您只需在程序包管理器控制台中使用此命令安装程序包:Install-Package System.Linq.Dynamic

    • {li>

      GitHub repository System.Linq.Dynamic

    • Scott Guthrie's blog post 关于动态LINQ(第1部分:使用LINQ动态查询库)

    选项2 - 在运行时创建Lambda表达式

    作为另一个选项,您可以在运行时创建lambda表达式,并将其与Where方法一起使用。例如,您可以创建以下方法:

    //Creates x=>x.Something == value
    public Expression<Func<T, bool>> EqualCriteria<T>(string propertyName, object value)
    {
        var property = typeof(T).GetProperty(propertyName);
        var x = Expression.Parameter(typeof(T), "x");
        var propertyExpression = Expression.Property(x, property.Name);
        var valueExpression = Expression.Convert(Expression.Constant(value),
            property.PropertyType);
        var criteria = Expression.Equal(propertyExpression, valueExpression);
        var lambda = Expression.Lambda<Func<T, bool>>(criteria, x);
        return lambda;
    }
    

    然后以这种方式使用它:

    var list = db.Products.ToList();
    var result = list.Where(EqualCriteria<Product>("Name", "product1").Compile()).ToList();
    

    正如您所看到的,在此解决方案中,您还可以动态使用列数据属性名称和值。

    选项3 - 在字典中使用预定义标准

    作为另一种选择,您可以创建包含所需条件的字典,然后动态使用它们。例如,假设您已创建以下字典:

    var criterias = new Dictionary<string, Func<Product, object, bool>>() {
        { "Id" , (p,v)=>p.Id.Equals(v) },
        { "Name" , (p,v)=>p.Name.Equals(v) }
    };
    

    然后根据列数据属性名称和单元格值,您只需使用以下语句来过滤列表:

    var list = db.Products.ToList();
    var result = list.Where(x => criterias["Name"](x, "product1")).ToList();
    

    选项4 - 使用if / else

    作为另一种选择,您可以简单地使用if / else条件。例如,假设您在字符串变量中具有对象变量和属性名称中的值,那么您可以编写:

    var list = db.Products.ToList();
    var result = list.ToList();
    if (propertyName == "Id")
    {
        result = result.Where(x=>x.Id == (int)value).ToList();
    }
    else if (propertyName == "Name")
    {
        result = result.Where(x=>x.Name == (string)value).ToList();
    }