Sto sviluppando il controllo utente in C # Visual Studio 2010 - una sorta di casella di testo "ricerca rapida" per filtrare datagridview. Dovrebbe funzionare per 3 tipi di origini dati datagridview: DataTable, DataBinding e DataSet. Il mio problema è con il filtraggio di DataTable dall'oggetto DataSet, che viene visualizzato su DataGridView.
Potrebbero esserci 3 casi (esempi per l'applicazione WinForm standard con DataGridView e TextBox su di esso) - i primi 2 funzionano bene, ho problemi con il terzo:
1. datagridview.DataSource = dataTable: funziona
quindi posso filtrare impostando: 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: funziona
quindi posso filtrare impostando: 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": non funziona
Succede quando si progetta una tabella utilizzando designer: inserire il DataSet da toolbox nel form, aggiungere dataTable ad esso e quindi impostare datagridview.DataSource = dataSource; e datagridview.DataMember = "TableName".
Il codice seguente finge queste operazioni:
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 lo provi, sebbene datatable sia filtrato (ds.Tables [0] .DefaultView.Count cambia), datagridview non viene aggiornato ... Ho cercato a lungo qualsiasi soluzione, ma il problema è che DataSource non può modificare - poiché è un controllo aggiuntivo, non voglio che rovini il codice del programmatore.
So che le possibili soluzioni sono:
- associare DataTable da DataSet utilizzando DataBinding e usarlo come esempio 2: ma spetta al programmatore durante la scrittura del codice,
- modificare dataSource in BindingSource, dataGridView.DataSource = dataSet.Tables [0], o a DefaultView programmaticamente: tuttavia, cambia il DataSource. Quindi la soluzione:
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());
}
non è accettabile, come vedi su dataSource di MessageBox sta cambiando ...
Non voglio farlo, perché è possibile che un programmatore scriva codice simile a questo:
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
}
Può farlo, poiché ha progettato DataGridView con DataSet e DataMember in designer. Il codice verrà compilato, tuttavia, dopo aver utilizzato un filtro, verrà generata un'eccezione ...
Quindi la domanda è: come posso filtrare DataTable in DataSet e mostrare i risultati su DataGridView senza cambiare DataSource in un altro? Perché posso filtrare DataTable dall'esempio 1 direttamente, mentre il filtro DataTable da DataSet non funziona? Forse non è DataTable associato a DataGridView in quel caso?
Si noti che il mio problema deriva dai problemi di progettazione, quindi la soluzione DEVE FUNZIONARE sull'esempio 3.