Filtrar DataGridView sin cambiar el origen de datos

Estoy desarrollando control de usuario en C # Visual Studio 2010 – una especie de cuadro de texto de “búsqueda rápida” para filtrar datagridview. Debería funcionar para 3 tipos de fonts de datos datagridview: DataTable, DataBinding y DataSet. Mi problema es con el filtrado de DataTable del objeto DataSet, que se muestra en DataGridView.

Podría haber 3 casos (ejemplos para la aplicación WinForm estándar con DataGridView y TextBox en él): los primeros 2 funcionan bien, tengo un problema con el tercero:

1. datagridview.DataSource = dataTable: funciona
entonces puedo filtrar estableciendo: 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: funciona
entonces puedo filtrar estableciendo: 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”: no funciona
Sucede cuando diseña una tabla con el diseñador: coloque el conjunto de datos de la caja de herramientas en el formulario, agréguelo a la tabla de datos y luego configure datagridview.DataSource = dataSource; y datagridview.DataMember = “TableName”.
El siguiente código simula estas operaciones:

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

Si lo prueba, aunque se filtra la tabla de datos (cambios en ds.Tables [0] .DefaultView.Count), datagridview no se actualiza … He estado buscando un largo tiempo para cualquier solución, pero el problema es que DataSource no puede cambio , ya que es un control adicional, no quiero que se estropee con el código del progtwigdor.

Sé que las posibles soluciones son:
– para enlazar DataTable desde DataSet usando DataBinding y usarlo como ejemplo 2: pero depende del progtwigdor durante la escritura del código,
– para cambiar dataSource a BindingSource, dataGridView.DataSource = dataSet.Tables [0], o a DefaultView programáticamente: sin embargo, cambia el DataSource. Entonces la solución:

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

no es aceptable, como puede ver en DataBox’s DataSource está cambiando …

No quiero hacer eso, porque es posible que un progtwigdor escriba código similar a este:

 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 } 

Él puede hacer eso, ya que diseñó DataGridView con DataSet y DataMember en el diseñador. El código se comstackrá, sin embargo, después de usar un filtro, arrojará una excepción …

Entonces la pregunta es: ¿cómo puedo filtrar DataTable en DataSet y mostrar los resultados en DataGridView sin cambiar DataSource a otro? ¿Por qué puedo filtrar DataTable del ejemplo 1 directamente, mientras que el filtrado de DataTable de DataSet no funciona? ¿Tal vez no sea DataTable enlazado a DataGridView en ese caso?

Tenga en cuenta que mi problema se debe al diseño de problemas, por lo que la solución DEBE FUNCIONAR en el ejemplo 3.

Acabo de pasar una hora con un problema similar. Para mí, la respuesta resultó ser embarazosamente simple.

 (dataGridViewFields.DataSource as DataTable).DefaultView.RowFilter = string.Format("Field = '{0}'", textBoxFilter.Text); 

Desarrollé una statement genérica para aplicar el filtro:

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

Los corchetes permiten espacios en el nombre de la columna.

Además, si desea incluir varios valores en su filtro, puede agregar la siguiente línea para cada valor adicional:

 rowFilter += string.Format(" OR [{0}] = '{1}'", columnName, additionalFilterValue); 

Una forma más simple es atravesar los datos y ocultar las líneas con la propiedad Visible .

 // Prevent exception when hiding rows out of view CurrencyManager currencyManager = (CurrencyManager)BindingContext[dataGridView3.DataSource]; currencyManager.SuspendBinding(); // Show all lines for (int u = 0; u < dataGridView3.RowCount; u++) { dataGridView3.Rows[u].Visible = true; x++; } // Hide the ones that you want with the filter you want. for (int u = 0; u < dataGridView3.RowCount; u++) { if (dataGridView3.Rows[u].Cells[4].Value == "The filter string") { dataGridView3.Rows[u].Visible = true; } else { dataGridView3.Rows[u].Visible = false; } } // Resume data grid view binding currencyManager.ResumeBinding(); 

Solo una idea ... me funciona.

Puede crear un objeto DataView a partir de su fuente de datos. Esto le permitiría filtrar y ordenar sus datos sin modificar directamente la fuente de datos.

Además, recuerde llamar a dataGridView1.DataBind(); después de configurar la fuente de datos.

// “Comment” Filter datagrid sin cambiar el conjunto de datos, funciona perfectamente.

  (dg.ItemsSource as ListCollectionView).Filter = (d) => { DataRow myRow = ((System.Data.DataRowView)(d)).Row; if (myRow["FName"].ToString().ToUpper().Contains(searchText.ToString().ToUpper()) || myRow["LName"].ToString().ToUpper().Contains(searchText.ToString().ToUpper())) return true; //if want to show in grid return false; //if don't want to show in grid }; 

Tengo una propuesta más clara sobre la búsqueda automática en un DataGridView

esto es un ejemplo

 private void searchTb_TextChanged(object sender, EventArgs e) { try { (lecteurdgview.DataSource as DataTable).DefaultView.RowFilter = String.IsNullOrEmpty(searchTb.Text) ? "lename IS NOT NULL" : String.Format("lename LIKE '{0}' OR lecni LIKE '{1}' OR ledatenais LIKE '{2}' OR lelieu LIKE '{3}'", searchTb.Text, searchTb.Text, searchTb.Text, searchTb.Text); } catch (Exception ex) { MessageBox.Show(ex.StackTrace); } } 

Encontré una manera simple de solucionar ese problema. En binding datagridview usted acaba de hacer: datagridview.DataSource = dataSetName.Tables["TableName"];

Si codificas como:

 datagridview.DataSource = dataSetName; datagridview.DataMember = "TableName"; 

el datagridview nunca volverá a cargar datos al filtrar.