Estou desenvolvendo o controle do usuário em C # Visual Studio 2010 - uma espécie de caixa de texto de "localização rápida" para filtrar o datagridview. Deve funcionar para 3 tipos de fontes de dados datagridview: DataTable, DataBinding e DataSet. Meu problema é filtrar DataTable do objeto DataSet, que é exibido em DataGridView.
Pode haver 3 casos (exemplos de aplicativo WinForm padrão com DataGridView e TextBox nele) - os 2 primeiros estão funcionando bem, tenho problema com o terceiro:
1. datagridview.DataSource = dataTable: funciona
para que eu possa filtrar definindo: 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
para que eu possa filtrar definindo: 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": não funciona
Acontece quando você projeta uma tabela usando o designer: coloque o DataSet da caixa de ferramentas no formulário, adicione dataTable a ele e então defina datagridview.DataSource = dataSource; e datagridview.DataMember = "TableName".
O código abaixo finge essas operações:
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());
}
Se você testá-lo - embora a tabela de dados seja filtrada (ds.Tables [0] .DefaultView.Count muda), o datagridview não é atualizado ... Há muito tempo que procuro uma solução, mas o problema é que o DataSource não pode mudança - como é um controle adicional, não quero atrapalhar o código do programador.
Eu sei que as soluções possíveis são:
- vincular DataTable a DataSet usando DataBinding e usá-lo como exemplo 2: mas cabe ao programador durante a escrita do código,
- alterar dataSource para BindingSource, dataGridView.DataSource = dataSet.Tables [0], ou para DefaultView programaticamente: no entanto, ele altera a DataSource. Portanto, a solução:
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());
}
não é aceitável, como você pode ver no dataSource do MessageBox está mudando ...
Não quero fazer isso, porque é possível que um programador escreva um código semelhante 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
}
Ele pode fazer isso, pois projetou DataGridView com DataSet e DataMember no designer. O código será compilado, porém, após usar um filtro, ele lançará uma exceção ...
Portanto, a questão é: como posso filtrar DataTable em DataSet e mostrar os resultados em DataGridView sem alterar DataSource para outro? Por que posso filtrar DataTable do exemplo 1 diretamente, enquanto filtrar DataTable do DataSet não está funcionando? Talvez não seja DataTable vinculado a DataGridView nesse caso?
Observe que meu problema decorre de problemas de design, portanto, a solução DEVE FUNCIONAR no exemplo 3.
Respostas:
Acabei de passar uma hora em um problema semelhante. Para mim, a resposta acabou sendo embaraçosamente simples.
fonte
IBindingListView
acordo com msdn.microsoft.com/en-us/library/…Object reference not set to an instance of an object.
para o GridView.Desenvolvi uma declaração genérica para aplicar o filtro:
Os colchetes permitem espaços no nome da coluna.
Além disso, se quiser incluir vários valores em seu filtro, você pode adicionar a seguinte linha para cada valor adicional:
fonte
Uma maneira mais simples é cruzar os dados e ocultar as linhas com a
Visible
propriedade.Apenas uma ideia ... funciona para mim.
fonte
DataGridView
, isso funcionou perfeitamente. :) Embora eu tenha usado umforeach
e atribuído diretamenterow.Visible = showAll || <condition>;
sem nenhumif
. IssoshowAll
é verdade se a string do filtro estiver vazia.Você pode criar um objeto DataView a partir de sua fonte de dados. Isso permitiria a você filtrar e classificar seus dados sem modificar diretamente a fonte de dados.
Além disso, lembre-se de ligar
dataGridView1.DataBind();
depois de definir a fonte de dados.fonte
// "Comentário" Filtrar datagrid sem alterar o conjunto de dados. Funciona perfeitamente.
fonte
Tenho uma proposta mais clara sobre a busca automática em um DataGridView
isto é um exemplo
fonte
Eu encontrei uma maneira simples de resolver esse problema. Ao vincular datagridview, você acabou de fazer:
datagridview.DataSource = dataSetName.Tables["TableName"];
Se você codificar como:
o datagridview nunca carregará dados novamente durante a filtragem.
fonte