[C#][WindowsForm] DataTable이 바인딩 된 DataGridView의 Row의 Visible 옵션을 조절하는 방법

강성준·2023년 12월 11일

DataTable을 DataSource로 Binding한, DataGridView의 Visible 필터링 기능

WindowsForm을 사용하다보면 다양한 Control들 중, 데이터를 보여주기위해 DataTable 과, DataGridView 를 자주 사용하게 됩니다.
DB에서 값을 불러오거나 엑셀 파일 등을 불러와 보여주기도 하는데 DataTableDataSource에 바인딩 해놓을 경우 DataTable의 값이 바뀌면 자동으로 DataGridView에 반영되어 매우 편리하기 때문입니다.

여러 부가기능을 개발하다보면 검색 기능을 도입해 키워드가 포함된 행(Row)만 나타내고 싶은 경우가 있습니다. 대부분의 경우에는 Foreach문을 통해 DataGridView.Rows를 순회하면서 가져온 DataRow.Visible 옵션을 False로 설정하여 필터링 하여 나타냅니다.

foreach (DataGirdViewRow row in dataGridView.Rows)
{
	// condition 1
	if (!row["Name"].Value.Contains("Kim"))
    {
    	row.Visible = false
    }
}

여기서 문제점은 바인딩된 데이터일 경우에 System.InvalidOperationException: '현재 위치 관리자의 위치와 관련된 행은 숨길 수 없습니다.' 라는 에러가 발생합니다.

대부분의 경우에는 CurrencyManager 클래스를 이용하여, 바인딩 되어있는 연결을 임시 적으로 끊고 작업을 마친 후에 다시 연결 하는 방법을 해답으로 제시하는 경우가 많았습니다.

CurrencyManager cm = (CurrencyManager)BindingContext[dataGridView.DataSource];
cm.SuspendBinding();

foreach (DataGirdViewRow row in dataGridView.Rows)
{
	// condition 1
	if (!row["Name"].Value.Contains("Kim")
    {
    	row.Visible = false
    }
}

cm.ResumeBinding();

이렇게 할 경우에 정상적으로 동작합니다. 다만 문제점은 프로그램에서 해당 부분이 자주 불리거나 혹은 확률적으로 row의 값이 Null 이라거나, 아니면 DataGridView에서 잡히지 않는 InvalidOperationException이 뜨면서 프로그램이 꺼지는 현상이 발생할 수 있었습니다.

그래서 바인딩된 DataGridViewRows.Visible 프로퍼티를 조절 할 경우에는 BindingSource를 활용하여 매우 간단하고, 속도빠르게 처리할 수 있습니다.
또한 DataGridView 가 필터링 되면서 ScrollBar가 조정되는 등의 느려지는 작업 없이 진행됩니다.

DataTable dataTable = new DataTable();
BindingSource bs = new BindingSource();

bs.DataSource = dataTable.DefaultView;
dataGridView.DataSource = bs;

다음과 같이 dataGridViewBindingSource로 선언된 bs 값에 DataTable를 연결하고, 다시 dataGridViewbs.DataSource로 설정합니다.

string serachText = "Kim";

bs.Filter = $"[Name] LIKE '%{searchText}%'";

와 같이 BindingSource.Filter를 활용하여 SQL문을 작성하듯이 괄호[] 안에 컬럼을 적은 후 LIKEIN 과 같은 필터구문을 적용하여 필터를 걸면 바로 DataGridView에서 반영된 행만 표시됩니다.
만약 필터를 없애고 다시 모든 데이터를 화면에 보여주기 위해서는 단 한줄의 메소드만 호출 하면 됩니다.

bs.RemoveFilter();

속도도 훨씬 빠르고 다양한 문제점을 해결하기도 합니다. 아무래도 직접 문자열 바탕으로 필터를 걸기 때문에 Row.Style로 직접 필터를 걸 수 없어 별도의 List<string>을 만들어 조건에 해당하는 문자열을 넣어 해당하는 열의 대표적인 이름을 넣어 다음과 같이 스타일에 해당하는 조건 또한 필터링 할 수 있었습니다.

List<string> filterRowName = new List<string>();

foreach (var row in dataGridView.Rows)
{
	if (row["Name"].Style.BackColor != Color.Empty)
    {
    	filterRowName.Add($"row["Name"].Value");
    }
}

bs.Filter = $"[Name] IN ( {string.Join(",", filterRowName.Select(x => $"'{x}'"))}";

이 외에 Row를 필터링 하는 DataTable.Select() 메소드를 호출하여 사용하는 방법도 있으니 참고하면 좋을 것 같습니다.

0개의 댓글