根据单元格值过滤datagridview中的对象列表 [英] Filtering list of objects in datagridview based on cell value

查看:73
本文介绍了根据单元格值过滤datagridview中的对象列表的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

给定一个对象:

I am currently unsure on the best way of going about getting a filter to work right on a datagridview that has its datasource set to a list of objects.

So given an object of:

    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表,看起来像这样:

I have a datagridview table that looks roughly like this:

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 

因此,当单击一个单元格时.假设第一列的第一个单元格.如果我右键单击一个单元格并在上下文菜单中选择一个选项,该选项为filter,则我需要显示datagridview表,其中仅包含具有相同帐号的行.在这种情况下,它将是第1行和第2行.为了执行此操作,我必须访问使用DepositAccountBill填充datagridview表的对象.因此,我需要做的就是查看,并且在我要查看的列中具有选定单元格的值.

So when clicking on a cell. Lets say the first cell on the first column. If I right click a cell and select an option in a context Menu that says filter I need to display the datagridview table with only rows that have the same Account number. In this case, it would be rows 1 and 2. In order for me to do this, I have to access the object that the datagridview table is populated with DepositAccountBill. So what I need to do is look and at the column I'm looking at has the selected cell's value.

因此,在我的方法中,到目前为止我没有尝试过:

So in my method I have tried thus far with no results:

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,因为它仅获取符合条件的对象列表.像这样:

I don't know if SELECT is the right LINQ method to use here or if this is even possible. I want to use WHERE because it only grabs the list of objects that match the condition. Something like this:

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

唯一的问题是 r.AccountNumber 取决于所选列的data属性.程序不知道基于选定单元格上的click事件的数据属性是什么.这就是为什么我认为反思可能是必要的.

Only problem is the r.AccountNumber is dependant on the data property of the selected column. The program does not know what the data property is based on a click event on the selected cell. This is why I think reflection might be necessary.

推荐答案

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

I suppose you know how to extract the property name using DataPropertyName property of the column and also how to get the value from Value property of the cell.

在答案中,我将重点介绍如何动态过滤具有 Property Name List< T> ,就像您使用 .Where(x => x.PropertyName ==值).

In the answer I'll focus on how to perform dynamic filtering a List<T> having Property Name and the Value, like when you use .Where(x=>x.PropertyName == Value).

要这样做,您可以选择几个选项,包括:

To do so, you have a couple of options which you can choose, including:

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

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

I'll share more details about above solutions and you can choose either of them.

注意: 如果答案太长,则最简单,最明显的答案可能是第四选择.

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

As an option you can add System.Linq.Dynamic reference to your project, then after using System.Linq.Dynamic namespace, you will be able to create dynamic queries on IEnumerable<T> or IQueryable<T> by passing criteria as string, for example:

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

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

This way you can simply use the column data property name and column value in the query dynamically. To find more about dynamic linq, take a look at following resources:

  • 用于 System.Linq的NuGet包动态.您可以简单地使用以下命令在软件包管理器控制台中安装软件包: Install-Package System.Linq.Dynamic

用于 System.Linq.Dynamic

斯科特·格思里(Scott Guthrie)的博客文章关于动态LINQ(第1部分:使用LINQ动态查询库)

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

As another option you can create lambda expression at run-time and use it with Where method. For example, you can create the following method:

//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;
}

然后以这种方式使用它:

And then use it this way:

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

如您所见,同样在此解决方案中,您可以动态使用列数据属性名称和值.

As you can see, also in this solution, you can use column data property name and value dynamically.

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

As another option you can create a dictionary containing the criteria which you need, then use them dynamically. For example let's say you've created the following dictionary:

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

然后基于列数据属性名称和单元格值,您可以简单地使用以下语句来过滤列表:

Then based on the column data property name and cell value, you can simply use the following statement to filter the list:

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

选项4-使用if/else

作为另一种选择,您可以简单地使用if/else条件.例如,假设您将值包含在对象变量中,并将属性名称包含在字符串变量中,则可以编写:

Option 4 - Using if/else

As another option you can use if/else conditions simply. For example let's say you've the value in an object variable and property name in a string variable, then you can write:

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

这篇关于根据单元格值过滤datagridview中的对象列表的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆