在不改变数据源的情况下过滤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在过滤时不会再次加载数据。