【问题标题】:Filtering list of objects in datagridview based on cell value根据单元格值过滤datagridview中的对象列表
【发布时间】:2018-05-22 17:50:17
【问题描述】:

我目前不确定让过滤器在数据源设置为对象列表的 datagridview 上正常工作的最佳方法。

所以给定一个对象:

    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 行。 为了让我这样做,我必须访问 datagridview 表中填充有 DepositAccountBill 的对象。所以我需要做的是查看并查看我正在查看的列具有所选单元格的值。

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

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 依赖于所选列的数据属性。程序不知道基于所选单元格上的单击事件的数据属性是什么。这就是为什么我认为反思可能是必要的。

【问题讨论】:

  • 你在什么情况下处理上面的代码?
  • 我正在处理来自所选单元格上的右键单击事件 (CellMouseUp) 的事件。

标签: c# .net winforms linq reflection


【解决方案1】:

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

在答案中,我将重点介绍如何对具有 Property Name 和 Value 的 List&lt;T&gt; 执行动态过滤,例如当你用.Where(x=&gt;x.PropertyName == Value)。

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

  1. 动态 Linq 库
  2. 在运行时动态创建Expression
  3. 使用 Dictionary 包含您对每个属性所需的条件
  4. 只需使用 if/else

我将分享有关上述解决方案的更多详细信息,您可以选择其中任何一个。


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


选项 1 - 动态 Linq 库

作为一个选项,您可以将System.Linq.Dynamic 引用添加到您的项目中,然后在使用System.Linq.Dynamic 命名空间后,您将能够通过将条件传递为string 在IEnumerable&lt;T&gt; 或IQueryable&lt;T&gt; 上创建动态查询,例如示例:

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

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

  • NuGet package 为System.Linq.Dynamic。您可以在包管理器控制台中使用此命令简单地安装包:Install-Package System.Linq.Dynamic

  • 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();
}

【讨论】:

    猜你喜欢
    • 2018-11-07
    • 1970-01-01
    • 2018-09-14
    • 1970-01-01
    • 2013-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多