在不更改数据源的情况下筛选 DataGridView

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

可能有3种情况(例如,带有 DataGridView 和 TextBox 的标准 WinForm 应用程序)——前2种工作正常,第3种有问题:

1. datagridview.DataSource = dataTable : it works
所以我可以通过设置: dataTable.DefaultView

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 进行过滤

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”: 它不工作
使用设计器设计表时会发生这种情况: 将工具箱中的 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());
}

如果您测试它-虽然数据表被过滤(ds. Tables [0] . DefaultView.Count 更改) ,datagridview 不会更新..。 I've been looking for a long time for any solution, but the problem is that DataSource 无法更改 - as it's additional control, I don't want it to mess up with programmer's code.

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

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
}

他可以这样做,因为他在设计器中使用 DataSet 和 DataMember 设计了 DataGridView。 Code will be compiled, however, after using a filter, it will throw an exception...

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

请注意,我的问题需要从设计问题,所以解决方案必须工作在例子3。

363362 次浏览

可以从数据源创建 DataView对象。这将允许您在不直接修改数据源的情况下筛选和排序数据。

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

我刚刚花了一个小时研究一个类似的问题,对我来说,答案简单得令人尴尬。

(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);

I found a simple way to fix that problem. At binding datagridview you've just done: datagridview.DataSource = dataSetName.Tables["TableName"];

如果你这样编码:

datagridview.DataSource = dataSetName;
datagridview.DataMember = "TableName";

the datagridview will never load data again when filtering.

//“注释”过滤数据网格而不改变数据集,完美工作。

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

一种更简单的方法是横向执行数据,并使用 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();

只是个想法... 对我有用。

我对 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);
}
}

For those of you who have implemented the checked answer yet still getting the error

(对象引用未设置为对象的实例)

正如注释中提到的,DataGridView 的数据源可能不属于 DataTable 类型,但如果属于,请再次尝试将数据表分配给 DataGridView 的数据源。 在我的示例中,我在 FormLoad ()中将数据表分配给 DataGridView 当我写这段代码的时候

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

它给了我上面提到的错误。所以,我再次将数据表重新分配给 dgv。所以代码是这样的

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

而且成功了。