2011-04-30 52 views
77

Estoy desarrollando control de usuario en C# Visual Studio 2010 - una especie de cuadro de diálogo de "búsqueda rápida" para filtrar datagridview. Debería funcionar para 3 tipos de fuentes de datos datagridview: DataTable, DataBinding y DataSet. Mi problema es filtrar DataTable del objeto DataSet, que se muestra en DataGridView.Filtrar DataGridView sin cambiar el origen de datos

Podría ser de 3 casos (ejemplos de aplicación WinForm estándar con DataGridView y TextBox en él) - 2 primeros están trabajando bien, no tengo problema con una tercera:

1. datagridview.DataSource = dataTable: funciona
para que pueda 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
por lo que se puede filtrar mediante el establecimiento de: bindingSource.Filter = "país como '% 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
Ocurre cuando diseña una tabla con el diseñador: coloque el DataSet de la caja de herramientas en el formulario, agregue dataTable y luego establezca datagridview.DataSource = dataSource; y datagridview.DataMember = "TableName".
código de abajo 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 el resultado es que - si bien se filtra tabla de datos (ds.Tables [0] cambios .DefaultView.Count), DataGridView no se actualiza ... he sido buscando un largo tiempo para cualquier solución, pero el problema es que DataSource no puede cambiar - como es control adicional, no quiero que se estropee con el código del programador.

Sé posibles soluciones son:
- para unirse DataTable del conjunto de datos utilizando DataBinding y utilizarlo como ejemplo 2: pero es responsabilidad del programador durante la escritura de código,
- para cambiar dataSource a BindingSource, dataGridView.DataSource = dataSet.Tables [0], o DefaultView programáticamente: sin embargo, cambia el DataSource. Así que 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, ya que se ve en dataSource del cuadro de mensaje está cambiando ...

yo no quiero hacer eso, porque es posible que un programador escribe código similar al siguiente:

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 
} 

Puede hacerlo, ya que diseñó DataGridView con DataSet y DataMember en el diseñador. El código se compilará, sin embargo, después de usar un filtro, lanzará 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 lleva desde el diseño de los problemas, por lo que la solución debe trabajar en el ejemplo 3.

+0

Mis 2 centavos, además de todos los comentarios y soluciones valiosas. Aquí hay un [artículo] (http://10tec.com/articles/datagridview-filter.aspx) que describe los pros y los contras del filtrado DataGridView enlazado a datos de esta manera y le brinda algunas ideas de cómo hacerlo mejor. – TecMan

+0

Disculpe la repetición pero creo que mi propuesta no funciona todo el tiempo. De hecho, a veces se levanta una excepción, que mi código es poco probable. Intentando filtrar con un bindingSource tienes todas las posibilidades de hacer un buen código. Como fecha: bindingSource.Filter = string.Format ..... –

Respuesta

105

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

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

cómo poner enlazar este evento al cuadro de texto –

+4

La sintaxis de filtrado se puede encontrar aquí: http://www.csharp-examples.net/dataview-rowfilter/ – Sal

+0

Usando una DataTable como la fuente evita el problema de tener que implementar 'IBindingListView 'según https://msdn.microsoft.com/en-us/library/system.windows.forms.bindingsource.filter(VS.90).aspx –

1

Se puede crear un objeto DataView 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 al dataGridView1.DataBind(); después de configurar la fuente de datos.

+2

Gracias por la respuesta. Sí, el objeto DataView se puede crear, sin embargo, cambia el tipo de DataSource, consulte el último código. Modifiqué la razón por la que quiero evitar eso en la publicación anterior. El método dataGridView1.DataBind() no existe en WinForms, supongo que es de ASP. – mj82

14

he desarrollado una declaración 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 el filtro, se puede añadir la siguiente línea para cada valor adicional:

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

he encontrado una manera sencilla de solucionar ese problema. En DataGridView de encuadernación que acaba de hacer: datagridview.DataSource = dataSetName.Tables["TableName"];

Si un código como:

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

DataGridView no cargará los datos de nuevo al filtrar.

0

// "Comment" Filtrar 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 
      };   
3

Una manera más simple y que es transversal a los datos, es ocultar las líneas con la propiedad visible.

// Muestra todas las líneas

 for (int u = 0; u < dataGridView3.RowCount; u++) 
     { 
      dataGridView3.Rows[u].Visible = true; 
      x++; 
     } 

// Ocultar los que usted desee con el filtro que desea.

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

Solo una idea ... para mi trabajo.

+0

Como alguien que está rellenando manualmente un 'DataGridView', esto funcionó perfectamente. :) Aunque utilicé un 'foreach' y directamente asigné' row.Visible = showAll || ; 'sin ningún' si'. That 'showAll' es verdadero si la cadena de filtro está vacía. – Andrew

0

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

Este 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); 
     } 
    } 
+0

Puede duplicar con http://stackoverflow.com/questions/5843537/filtering-datagridview-without-changing-datasource –

Cuestiones relacionadas