Фильтрация DataGridView без изменения источника данных
я разрабатываю пользовательский элемент управления в C# Visual Studio 2010-своего рода текстовое поле" Быстрый поиск " для фильтрации datagridview. Он должен работать на 3 видах управления datagridview источники: таблицы данных, привязки данных и наборов данных. Моя проблема заключается в фильтрации DataTable из объекта DataSet, который отображается на DataGridView.
может быть 3 случая (примеры для стандартного приложения WinForm с DataGridView и TextBox на нем) - первые 2 работают нормально, у меня проблема с 3-м один:
1. практическое руководство.DataSource = dataTable: он работает
поэтому я могу фильтровать, устанавливая: dataTable.DefaultView.RowFilter = "страна как' %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. практическое руководство.DataSource = bindingSource: это работает
поэтому я могу фильтровать, установив: 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. практическое руководство.DataSource = источник данных; datagridview.DataMember = "TableName": это не так работа
Это происходит при проектировании таблицы с помощью конструктора: поместите набор данных из toolbox в форму, добавьте в него dataTable, а затем установите datagridview.DataSource = источник данных; и datagridview.DataMember = "TableName".
Код ниже делает вид, что эти операции:
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());
}
если вы проверяете его-Хотя datatable фильтруется (ds.Таблицы[0].DefaultView.Количество изменений), datagridview не обновляется... Я долго искал любое решение, но проблема в том, что источник данных не может измениться - поскольку это дополнительный контроль, я не хочу, чтобы он испортил код программиста.
Я знаю, что возможные решения:
- чтобы привязать DataTable из DataSet с помощью DataBinding и использовать его в качестве примера 2: но это зависит от программиста во время написания кода,
- чтобы изменить источник данных на BindingSource, dataGridView.Источник данных = dataSet.Таблицы[0], или к DefaultView программно: однако, он изменяет источник данных. Так что решение:
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());
}
не приемлемо, как вы видите на источнике данных MessageBox меняется...
Я не хочу этого делать, потому что возможно программист пишет код, подобный этому:
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
}
Он может это сделать, так как он разработал DataGridView с DataSet и DataMember в designer. Код будет скомпилирован, однако после использования фильтра он выдаст исключение...
Итак, вопрос: как я могу отфильтровать DataTable в DataSet и показать результаты на DataGridView без изменения источника данных на другой? Почему я могу фильтровать DataTable из примера 1 напрямую, в то время как фильтрация DataTable из DataSet не работает? Может быть, это не DataTable привязан к DataGridView в этом случае?
обратите внимание, что моя проблема связана с проблемами проектирования, поэтому решение должно работать на примере 3.
7 ответов:
Я только что потратил час на подобную проблему. Для меня ответ оказался донельзя прост.
(dataGridViewFields.DataSource as DataTable).DefaultView.RowFilter = string.Format("Field = '{0}'", textBoxFilter.Text);
Я разработал общий оператор для применения фильтра:
string rowFilter = string.Format("[{0}] = '{1}'", columnName, filterValue); (myDataGridView.DataSource as DataTable).DefaultView.RowFilter = rowFilter;
квадратные скобки позволяют использовать пробелы в имени столбца.
кроме того, если вы хотите включить несколько значений в фильтре, вы можете добавить следующую строку для каждого дополнительного значения:
rowFilter += string.Format(" OR [{0}] = '{1}'", columnName, additionalFilterValue);
более простой способ-пересечь данные и скрыть строки с помощью
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();
просто идея... это работает на меня.
вы можете создать DataView объект из вашего источника данных. Это позволит вам фильтровать и сортировать данные без непосредственного изменения данных.
кроме того, не забудьте позвонить
dataGridView1.DataBind();
после установки источника данных.
/ / "комментарий" фильтр datagrid без изменения набора данных, отлично работает.
(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 };
У меня есть более четкое предложение по автоматическому поиску в DataGridView
пример
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); } }
Я нашел простой способ решить эту проблему. При привязке datagridview вы только что сделали:
datagridview.DataSource = dataSetName.Tables["TableName"];
Если вы код:
datagridview.DataSource = dataSetName; datagridview.DataMember = "TableName";
datagridview никогда не будет загружать данные снова при фильтрации.