在不改变数据源的情况下过滤DataGridView

我正在开发C#Visual Studio 2010中的用户控件 – 一种用于过滤datagridview的“快速查找”文本框。 它应该适用于3种types的datagridview数据源:DataTable,DataBinding和DataSet。 我的问题是从数据集对象,它显示在DataGridView中筛选DataTable。

可能有3种情况(标准WinForm应用程序与DataGridView和TextBox的例子) – 前2个工作正常,我有问题与第三个:

1. datagridview.DataSource = dataTable:它的工作原理
所以我可以通过设置来过滤: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:它的工作原理
所以我可以通过设置来过滤: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”:它不起作用
这发生在你使用devise器devise一个表时:把DataSet从工具箱放在表单上,​​向其中添加dataTable,然后设置datagridview.DataSource = 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()); } 

如果你testing它 – 尽pipedatatable过滤(ds.Tables [0] .DefaultView.Count更改),datagridview不更新…我一直在寻找任何解决scheme的很长一段时间,但问题是, DataSource不能改变 – 因为它是额外的控制,我不希望它搞乱程序员的代码。

我知道可能的解决scheme是:
– 使用DataBinding从DataSet绑定DataTable,并将其用作示例2:但在代码编写期间取决于程序员,
– 将dataSource更改为BindingSource,dataGridView.DataSource = dataSet.Tables [0],或以编程方式将其更改为DefaultView:但是,它更改了DataSource。 所以解决scheme:

 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的dataSource正在改变…

我不想这样做,因为程序员可能会写类似于这样的代码:

 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 } 

他可以这样做,因为他在devise器中使用DataSet和DataMemberdeviseDataGridView。 代码将被编译,但是,使用filter后,它会抛出一个exception…

所以问题是:如何过滤DataSet中的DataTable,并在DataGridView上显示结果而不将DataSource更改为另一个? 为什么我可以直接从示例1过滤DataTable,而从DataSet过滤DataTable不起作用? 在这种情况下可能不是DataTable绑定到DataGridView?

请注意,我的问题来自devise问题,所以解决scheme必须在示例3上工作。

我刚刚在一个类似的问题上花了一个小时。 对我来说,答案简直太尴尬了。

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

我开发了一个通用语句来应用filter:

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

方括号允许列名称中的空格。

另外,如果要在filter中包含多个值,则可以为每个附加值添加以下行:

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

一个简单的方法是横向于数据,是隐藏可见属性的行。

//显示所有行

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

//用你想要的filter隐藏你想要的。

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

只是一个想法…为mi作品。

你可以从你的数据源创build一个DataView对象。 这将允许您筛选和sorting数据,而无需直接修改数据源。

另外,请记住调用dataGridView1.DataBind(); 设置数据源后。

//“注释”在不更改数据集的情况下过滤数据网格,完美工作。

  (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自动search

这是一个例子

 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在过滤时不会再次加载数据。