Filter Datagrid View from data populated from entity in C#

懵懂的女人 提交于 2021-02-11 12:54:28

问题


I am newbie in C# and probably this might be a possible duplicate but am unable to do filter of records on datagrid view whose columns were designed from designer view on TextBox change event.

This is my code to populate the datagridview. Any help will be highly appreciated.

IList<ProductEntity> emp = HibernateDao.fetchDAta();

IList<ProductModel> products = new List<ProductModel>();

foreach(ProductEntity e in emp)
{
    dataGridView1.Rows.Add("" + e.id, e.barcode, e.product_name, e.product_desc, e.quantity + " " + e.units,""+e.buying_price,e.retail_selling_price,e.can_sell_whole_sale,e.whole_selling_price);
}

And this is the code that have tried to do filter which is not working at all

BindingSource bs=new BindingSource();

private void metroTextBox1_TextChanged(object sender, EventArgs e)
{


   if (metroTextBox1.Text == string.Empty)
    {
        bs.RemoveFilter();
    }
    else
    {
        bs.Filter = string.Format("product_name LIKE '*{0}*'", metroTextBox1.Text);
    }
 


}

and is the datagrid view designed from designer that i need to filter


回答1:


Consider something more like this:

IList<ProductEntity> emp = HibernateDao.fetchDAta();

//seems no-op, did you miss a mapping call? : IList<ProductModel> products = new List<ProductModel>();

BindingSource bs = new BindingSource();
bs.DataSource = emp; //emp will need to be a bindable list; does fetchData do a ToList() ?

bs.Filter = "[product_name] = 'cornflakes'";

dataGridView1.Columns.Clear();
dataGridView1.AutoGenerateColumns = true;
dataGridView1.DataSource = bs;

You can't get DataGridView to show two properties in a single column, so e.quantity + " " + e.units type things won't work out. You'll have to add a property (not field) to ProductModel, that returns those two values as a single string

Databinding isn't a complicated thing. In some senses you're already doing part of it. That loop you had that iterated the data model and stuffed everything into the grid - databinding will do that for you, if you just set the datasource of the grid to a list that supports binding then the grid will create one row per list item (and in autogeneratecolumns mode it will make one column per simple property it finds). The more trick aspect of binding is that when you change the model (and you should change the data by changing the model, not programmatically altering the grid cells), the grid updates to reflect the changes

It helps achieve the separation of concerns that model/view/controller represents


Edit:

If HibernateDao.fetchDAta() returns something that doesn't implement the IBindingListView interface you could consider:

  1. To install the nuget package morelinq; it has methods to turn lists of objects into datatables, and datatables fully support filtering, OR

  2. To install the nuget package System.Linq.Dynamic; it can allow you to query things with linq by writing string expressions

Make a new project and completely replace the contents of Form1.vb with this demo:

Imports System.Linq.Dynamic
Imports MoreLinq

Public Class Form1

    Class Person
        Property Name As String
        Property Age As Integer

    End Class

    Private dgvDL As New DataGridView
    Private dgvBLV As New DataGridView
    Private tb As New TextBox
    Private people As List(Of Person)

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load



        Dim names() = {"John", "James"}
        people = names.Select(Function(x) New Person With {.Name = x, .Age = x.Length * 7}).ToList()


        'dynamic linq dgv 
        dgvDL.DataSource = people
        Me.Controls.Add(dgvDL)

        'morelinq DGV
        Dim bs As New BindingSource
        bs.DataSource = people.ToDataTable()
        dgvBLV.DataSource = bs
        Me.Controls.Add(dgvBLV)





        'irrelevant UI code
        AddHandler tb.TextChanged, AddressOf TextChange
        Me.Controls.Add(tb)
        dgvBLV.Location = New Point(dgvDL.Right, dgvDL.Top) 'place adjacent to above grid
        tb.Location = New Point(dgvDL.Left, dgvDL.Height)
    End Sub

    Private Sub TextChange(sender As Object, e As EventArgs)
        If (tb.Text = "") Then
            dgvDL.DataSource = people 'filter DL grid
            DirectCast(dgvBLV.DataSource, BindingSource).RemoveFilter() 'filter BLV grid
        Else
            dgvDL.DataSource = people.Where("Name == @0", tb.Text).ToList() 'filter DL grid
            DirectCast(dgvBLV.DataSource, BindingSource).Filter = $"[Name] = '{tb.Text}'" 'filter BLV grid
        End If
    End Sub


End Class

Note, if you're prepared to filter things using LINQ that doesnt use a built string filter, you don't need either of these helper libs; you can just use normal LINQ - see in the TextChange method I say .Where("Name == @0", tb.Text) - because Name is hardcoded here, this could just as easily be .Where(Function(x) x.Name = tb.Text). Dynamic LINQ only really makes your life a bit easier if you're constructing the left side too

--

Edit

C# version, not a huge departure from the VB. Not sure why my brain slipped into VB.NET, but I've left the VB above for you to compare with this, as a "that's how to read VB".. The two languages are nearly the same these days, but for a couple of keywords and semicolons, and it's always handy to know how to read other flavors of .NET:

using System.Linq.Dynamic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
using System;
using System.Collections.Generic;
using MoreLinq;

namespace WindowsFormsApp1
{


    public partial class Form1: Form
    {
        public Form1()
        {
            base.Load += Form1_Load;
        }

        public partial class Person
        {
            public string Name { get; set; }
            public int Age { get; set; }
        }

        private DataGridView dgvDL = new DataGridView();
        private DataGridView dgvBLV = new DataGridView();
        private TextBox tb = new TextBox();
        private List<Person> people;

        private void Form1_Load(object sender, EventArgs e)
        {
            var names = new string[] { "John", "James" };
            people = names.Select(x => new Person() { Name = x, Age = x.Length * 7 }).ToList();


            // dynamic linq dgv 
            dgvDL.DataSource = people;
            this.Controls.Add(dgvDL);

            // morelinq DGV
            var bs = new BindingSource();
            bs.DataSource = people.ToDataTable();
            dgvBLV.DataSource = bs;
            this.Controls.Add(dgvBLV);





            // irrelevant UI code
            this.tb.TextChanged += TextChange;
            this.Controls.Add(tb);
            dgvBLV.Location = new Point(dgvDL.Right, dgvDL.Top); // place adjacent to above grid
            tb.Location = new Point(dgvDL.Left, dgvDL.Height);
        }

        private void TextChange(object sender, EventArgs e)
        {
            if (tb.Text == "")
            {
                dgvDL.DataSource = people; // filter DL grid
                ((BindingSource)dgvBLV.DataSource).RemoveFilter(); // filter BLV grid
            }
            else
            {
                dgvDL.DataSource = people.Where("Name == @0", tb.Text).ToList(); // filter DL grid
                ((BindingSource)dgvBLV.DataSource).Filter = $"[Name] = '{tb.Text}'";
            } // filter BLV grid
        }
    }
}


来源:https://stackoverflow.com/questions/63245000/filter-datagrid-view-from-data-populated-from-entity-in-c-sharp

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!