데이터 소스를 변경하지 않고 DataGridView 필터링


95

저는 C # Visual Studio 2010에서 사용자 정의 컨트롤을 개발 중입니다. 즉, datagridview를 필터링하기위한 일종의 "빠른 찾기"텍스트 상자입니다. DataTable, DataBinding 및 DataSet의 3 가지 유형의 datagridview 데이터 소스에 대해 작동해야합니다. 내 문제는 DataGridView에 표시되는 DataSet 개체에서 DataTable을 필터링하는 것입니다.

3 가지 경우 (DataGridView 및 TextBox가있는 표준 WinForm 응용 프로그램의 예)가있을 수 있습니다. 처음 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": 작동하지 않습니다
. 디자이너를 사용하여 테이블을 디자인 할 때 발생합니다. 도구 상자의 DataSet을 폼에 넣고 dataTable을 추가 한 다음 set 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());
}

테스트하면-datatable이 필터링되었지만 (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을 필터링하고 DataSource를 다른 것으로 변경하지 않고 DataGridView에 결과를 표시 할 수 있습니까? DataSet에서 DataTable 필터링이 작동하지 않는 동안 예제 1에서 DataTable을 직접 필터링 할 수있는 이유는 무엇입니까? 이 경우 DataGridView에 바인딩 된 DataTable이 아닐까요?

내 문제는 디자인 문제에서 발생하므로 솔루션은 예제 3에서 작동해야합니다.


1
모든 귀중한 의견 및 솔루션에 추가로 2 센트. 다음은 이러한 방식으로 데이터 바인딩 된 DataGridView를 필터링 할 때의 장단점을 설명하고 더 나은 방법에 대한 몇 가지 아이디어를 제공 하는 문서 입니다.
TecMan

반복해서 실례하지만 내 제안이 매번 작동하지 않는 것 같습니다. 실제로 때때로 예외가 해제되어 내 코드는 거의 없습니다. bindingSource로 필터링하려고하면 좋은 코드를 만들 수있는 모든 기회가 있습니다. 좋아요 날짜 :
bindingSource.Filter

나는 TecMan 코멘트를 좋아합니다. 필터 속성 (덜 작동하지만 실제로는 ADO.Net Datatable에서만 사용할 수 있음)을 통해 필터링 작업을 IBindingListView 인터페이스에 위임하거나 컨트롤에서 전체 작업을 수행 할 수 있습니다 (더 많이 작동하지만 모든 작업에서 작동해야 함).
Marco Guignard

답변:


144

비슷한 문제에 한 시간을 보냈습니다. 저에게 대답은 당황 할 정도로 간단했습니다.

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

2
어떻게 텍스트 상자에이 이벤트 바인딩 넣어
아룬 프라 사드 ES

7
필터링 구문은 다음에서 찾을 수 있습니다. csharp-examples.net/dataview-rowfilter
Sal

DataTable을 사용하면 소스 구현해야하는 문제를 해결수록 IBindingListView에 따라 msdn.microsoft.com/en-us/library/...을
제레미 톰슨

이 오류가 발생합니다 : Object reference not set to an instance of an object.GridView.
Si8

데이터 소스는 무엇입니까? 내 예에서는 DataTable을 사용하고 있다고 가정합니다. 다른 것을 사용하는 경우 캐스팅을 확인하십시오. 내 예에서 "as DataTable".
Brad Bruce

23

필터를 적용하기 위해 일반적인 문을 개발했습니다.

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

대괄호는 열 이름에 공백을 허용합니다.

또한 필터에 여러 값을 포함하려면 각 추가 값에 대해 다음 행을 추가 할 수 있습니다.

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

12

더 간단한 방법은 데이터를 가로 질러 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이것은 완벽하게 작동했습니다. :) 내가 사용하지만 foreach직접 할당 row.Visible = showAll || <condition>;어떤없이 if. 즉 showAll필터 문자열이 비어 마찬가지입니다.
앤드류

이 경우 우리는 데이터 소스 유형에 묶여 있지 않기 때문에 좋은 생각입니다. 아니 어떤 DataTable.
mshakurov

완벽하게 작동했으며 검색 로직을 개선하기 위해 if 조건을 dataGridView3.Rows [u] .Cells [4] .Value.ToString (). IndexOf ( "The filter string")> = 0
Ali Ali

1

데이터 소스에서 DataView 개체를 만들 수 있습니다 . 이렇게하면 데이터 소스를 직접 수정하지 않고도 데이터를 필터링하고 정렬 할 수 있습니다.

또한 dataGridView1.DataBind();데이터 소스를 설정 한 후 호출 해야합니다.


2
답변 주셔서 감사합니다. 예, DataView 개체를 만들 수 있지만 DataSource 유형이 변경됩니다. 마지막 코드를 참조하십시오. 나는 이전 게시물에서 그것을 피하고 싶은 이유를 수정했습니다. dataGridView1.DataBind () 메서드는 WinForms에 존재하지 않으며 ASP에서 가져온 것으로 가정합니다.
mj82

0

// "Comment"데이터 셋을 변경하지 않고 데이터 그리드 필터링, 완벽하게 작동합니다.

            (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

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


-2

그 문제를 해결하는 간단한 방법을 찾았습니다. 바인딩 datagridview에서 방금 완료했습니다.datagridview.DataSource = dataSetName.Tables["TableName"];

다음과 같이 코딩하면 :

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

datagridview는 필터링 할 때 데이터를 다시로드하지 않습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.