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

时间:2011-04-30 17:45:15

标签: c# winforms visual-studio-2010 datagridview filter

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

可能有3个案例(标准WinForm应用程序的示例,其中包含DataGridView和TextBox) - 前2个工作正常,我遇到第3个问题:

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”:它不起作用
当您使用designer设计表时会发生这种情况:将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不会更新... 我一直在寻找任何解决方案的长时间,但问题是 DataSource无法改变 - 因为它是额外的控制,我不希望它搞乱程序员的代码。

我知道可能的解决方案是:
- 使用DataBinding从DataSet绑定DataTable并将其用作示例2:但是在代码编写期间由程序员决定, - 将dataSource更改为BindingSource,dataGridView.DataSource = dataSet.Tables [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。 代码将被编译,但是,在使用过滤器后,它将引发异常......

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

请注意,我的问题来自设计问题,所以解决方案必须在示例3中工作。

8 个答案:

答案 0 :(得分:121)

我只花了一个小时来解决类似的问题。对我来说,答案结果是令人尴尬的简单。

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

答案 1 :(得分:19)

我开发了一个通用语句来应用过滤器:

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

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

此外,如果要在过滤器中包含多个值,可以为每个附加值添加以下行:

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

答案 2 :(得分:6)

更简单的方法是横向数据,并隐藏具有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();

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

答案 3 :(得分:1)

您可以从数据源创建DataView对象。这样您就可以在不直接修改数据源的情况下对数据进行过滤和排序。

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

答案 4 :(得分:1)

对于那些已经实施了检查答案但仍然出现错误的人

<块引用>

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

正如评论中提到的,也许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);

它奏效了。

答案 5 :(得分:0)

//“注释”过滤数据网格而不更改数据集,完美无缺。

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

答案 6 :(得分:0)

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

答案 7 :(得分:-2)

我找到了解决这个问题的简单方法。在绑定datagridview时,您刚刚完成了:datagridview.DataSource = dataSetName.Tables["TableName"];

如果你的代码如下:

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

datagridview在过滤时永远不会再次加载数据。