web-dev-qa-db-ja.com

データソースを変更せずにDataGridViewをフィルタリングする

私は、C#Visual Studio 2010でユーザーコントロールを開発しています。これは、datagridviewをフィルタリングするための一種の「クイック検索」テキストボックスです。 3つのタイプのdatagridviewデータソースで動作するはずです:DataTable、DataBinding、およびDataSet。私の問題は、DataGridViewに表示されるDataSetオブジェクトからDataTableをフィルタリングすることです。

3つの場合があります(DataGridViewとTextBoxを含む標準のWinFormアプリケーションの例)-最初の2つは問題なく動作し、3つ目の問題があります:

1。datagridview.DataSource = dataTable:it works
したがって、次の設定でフィルタリングできます: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:it works
次のように設定してフィルタリングできます: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());
}

。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は更新されません...解決策を探していましたが、問題はそれです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に結果を表示するにはどうすればよいですか。例1のDataTableを直接フィルタリングできるのに、DataSetのDataTableをフィルタリングできないのはなぜですか?その場合、DataGridViewにバインドされたDataTableではないのでしょうか?

私の問題は問題の設計から取っているため、ソリューションは例3で機能する必要があることに注意してください。

87
mj82

同様の問題に1時間を費やしました。私にとって、答えは恥ずかしいほど単純であることがわかりました。

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

フィルターを適用する一般的なステートメントを作成しました。

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

角括弧では、列名にスペースを使用できます。

さらに、フィルターに複数の値を含める場合は、追加の値ごとに次の行を追加できます。

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

より簡単な方法は、データを横断し、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();

ただのアイデア...それは私のために働く。

6
João Moreira

データソースから DataView オブジェクトを作成できます。これにより、データソースを直接変更せずにデータをフィルタリングおよびソートできます。

また、データソースを設定した後にdataGridView1.DataBind();を呼び出すことを忘れないでください。

1
epotter

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);
        }
    }
0
KOUAKEP ARNOLD

//「コメント」データセットを変更せずにデータグリッドをフィルタリングし、完全に機能します。

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