Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Filtering DataGridView without changing datasource

I'm developing user control in C# Visual Studio 2010 - a kind of "quick find" textbox for filtering datagridview. It should work for 3 types of datagridview datasources: DataTable, DataBinding and DataSet. My problem is with filtering DataTable from DataSet object, which is displayed on DataGridView.

There could be 3 cases (examples for standard WinForm application with DataGridView and TextBox on it) - first 2 are working OK, I've problem with 3rd one:

1. datagridview.DataSource = dataTable : it works
so I can filter by setting: dataTable.DefaultView.RowFilter = "country LIKE '%s%'";

DataTable dt = new DataTable();  private void Form1_Load(object sender, EventArgs e) {     dt.Columns.Add("id", typeof(int));     dt.Columns.Add("country", typeof(string));      dt.Rows.Add(new object[] { 1, "Belgium" });     dt.Rows.Add(new object[] { 2, "France" });     dt.Rows.Add(new object[] { 3, "Germany" });     dt.Rows.Add(new object[] { 4, "Spain" });     dt.Rows.Add(new object[] { 5, "Switzerland" });     dt.Rows.Add(new object[] { 6, "United Kingdom" });      dataGridView1.DataSource = dt; }  private void textBox1_TextChanged(object sender, EventArgs e) {     MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString());      dt.DefaultView.RowFilter = string.Format("country LIKE '%{0}%'", textBox1.Text);      MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString()); }  

2. datagridview.DataSource = bindingSource: it works
so I can filter by setting: bindingSource.Filter = "country LIKE '%s%'";

DataTable dt = new DataTable(); BindingSource bs = new BindingSource();  private void Form1_Load(object sender, EventArgs e) {     dt.Columns.Add("id", typeof(int));     dt.Columns.Add("country", typeof(string));      dt.Rows.Add(new object[] { 1, "Belgium" });     dt.Rows.Add(new object[] { 2, "France" });     dt.Rows.Add(new object[] { 3, "Germany" });     dt.Rows.Add(new object[] { 4, "Spain" });     dt.Rows.Add(new object[] { 5, "Switzerland" });     dt.Rows.Add(new object[] { 6, "United Kingdom" });      bs.DataSource = dt;     dataGridView1.DataSource = bs; }  private void textBox1_TextChanged(object sender, EventArgs e) {     MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString());      bs.Filter = string.Format("country LIKE '%{0}%'", textBox1.Text);      MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString()); } 

3. datagridview.DataSource = dataSource; datagridview.DataMember = "TableName": it doesn't work
It happens when you design a table using designer: put the DataSet from toolbox on form, add dataTable to it and then set datagridview.DataSource = dataSource; and datagridview.DataMember = "TableName".
Code below pretends these operations:

DataSet ds = new DataSet(); DataTable dt = new DataTable();  private void Form1_Load(object sender, EventArgs e) {     dt.Columns.Add("id", typeof(int));     dt.Columns.Add("country", typeof(string));      dt.Rows.Add(new object[] { 1, "Belgium" });     dt.Rows.Add(new object[] { 2, "France" });     dt.Rows.Add(new object[] { 3, "Germany" });     dt.Rows.Add(new object[] { 4, "Spain" });     dt.Rows.Add(new object[] { 5, "Switzerland" });     dt.Rows.Add(new object[] { 6, "United Kingdom" });      ds.Tables.Add(dt);     dataGridView1.DataSource = ds;     dataGridView1.DataMember = dt.TableName; }  private void textBox1_TextChanged(object sender, EventArgs e) {     MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString());       //it is not working     ds.Tables[0].DefaultView.RowFilter = string.Format("country LIKE '%{0}%'", textBox1.Text);      MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString()); } 

If you test it - although datatable is filtered (ds.Tables[0].DefaultView.Count changes), datagridview is not updated... I've been looking for a long time for any solution, but the problem is that DataSource cannot change - as it's additional control, I don't want it to mess up with programmer's code.

I know possible solutions are:
- to bind DataTable from DataSet using DataBinding and use it as example 2: but it's up to the programmer during code writing,
- to change dataSource to BindingSource, dataGridView.DataSource = dataSet.Tables[0], or to DefaultView programatically: however, it changes the DataSource. So the solution:

private void textBox1_TextChanged(object sender, EventArgs e) {     MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString(), ds.Tables[0].DefaultView.Count.ToString());      DataView dv = ds.Tables[0].DefaultView;     dv.RowFilter = string.Format("country LIKE '%{0}%'", textBox1.Text);     dataGridView1.DataSource = dv;      MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString(), ds.Tables[0].DefaultView.Count.ToString()); } 

is not acceptable, as you see on MessageBox's dataSource is changing...

I don't want to do that, because it's possible a programmer writes code similar to this:

private void textBox1_TextChanged(object sender, EventArgs e) {     MessageBox.Show("DataSource type BEFORE = " + dataGridView1.DataSource.GetType().ToString(), ds.Tables[0].DefaultView.Count.ToString());      DataSet dsTmp = (DataSet)(dataGridView1.DataSource);   //<--- it is OK       DataView dv = ds.Tables[0].DefaultView;     dv.RowFilter = string.Format("country LIKE '%{0}%'", textBox1.Text);     dataGridView1.DataSource = dv;   //<--- here the source is changeing from DataSet to DataView      MessageBox.Show("DataSource type AFTER = " + dataGridView1.DataSource.GetType().ToString(), ds.Tables[0].DefaultView.Count.ToString());      dsTmp = (DataSet)(dataGridView1.DataSource);    //<-- throws an exception: Unable to cast object DataView to DataSet } 

He can do that, as he designed DataGridView with DataSet and DataMember in designer. Code will be compiled, however, after using a filter, it will throw an exception...

So the question is: how can I filter DataTable in DataSet and show the results on DataGridView without changing DataSource to another? Why I can filter DataTable from example 1 directly, while filtering DataTable from DataSet is not working? Maybe it's not DataTable bound to DataGridView in that case?

Please note, that my problem takes from designing issues, so the solution MUST WORK on example 3.

like image 863
mj82 Avatar asked Apr 30 '11 17:04

mj82


People also ask

How do I filter in C#?

C# filter list with iteration. In the first example, we use a foreach loop to filter a list. var words = new List<string> { "sky", "rock", "forest", "new", "falcon", "jewelry" }; var filtered = new List<string>(); foreach (var word in words) { if (word. Length == 3) { filtered.

What is DataGridView in C#?

The DataGridView control provides a customizable table for displaying data. The DataGridView class allows customization of cells, rows, columns, and borders through the use of properties such as DefaultCellStyle, ColumnHeadersDefaultCellStyle, CellBorderStyle, and GridColor.


2 Answers

I just spent an hour on a similar problem. For me the answer turned out to be embarrassingly simple.

(dataGridViewFields.DataSource as DataTable).DefaultView.RowFilter = string.Format("Field = '{0}'", textBoxFilter.Text); 
like image 50
Brad Bruce Avatar answered Sep 23 '22 04:09

Brad Bruce


I developed a generic statement to apply the filter:

string rowFilter = string.Format("[{0}] = '{1}'", columnName, filterValue); (myDataGridView.DataSource as DataTable).DefaultView.RowFilter = rowFilter; 

The square brackets allow for spaces in the column name.

Additionally, if you want to include multiple values in your filter, you can add the following line for each additional value:

rowFilter += string.Format(" OR [{0}] = '{1}'", columnName, additionalFilterValue); 
like image 43
Joe Sisk Avatar answered Sep 22 '22 04:09

Joe Sisk