[WPF] DataGrid 동적 컨트롤 추가 시 오작동 문제

mina_dev·2022년 9월 2일
0

WPF로 DataGrid 컴포넌트 이용 시 발생한 문제 해결 과정을 정리하였습니다.

🟤 DataGrid를 이용하여 TreeView 구현하기

TreeView를 이용하여 동적으로 TreeViewItem을 생성하고 구현하였습니다. 하지만 조금 더 깔끔한 화면 구성을 위해 DataGrid로 변경하기로 결정하였습니다.

🔍 DataGrid로 TreeView 구현한 오픈소스 검색

  • 많은 유료버전의 컨트롤을 제외하고 TreeView 구조를 유지하면서도 Name 컬럼을 제가 원하는 컴포넌트를 구성하여 동적으로 구성할 수 있는 소스코드를 찾았습니다.

    참조한 소스코드 : WPF TreeGrid using a DataGrid
    WPF TreeGrid using a DataGrid Image


🤨 스크롤할 때 발생하는 이 문제! 오픈소스 버그인가?

1. 컨트롤 값을 변경해도 binding한 변수의 set 함수 호출이 되지 않음

  • 디버깅 메시지를 출력하게 하거나 디버깅 포인트를 지정한 후 실행하였을 때 아무 이벤트가 발생하지 않았습니다.

2. 스크롤이 생기는 경우 스크롤을 위아래로 움직일 때 체크박스 랜덤으로 선택 및 해제되는 현상

  • Template을 여러 종류로 구현하여 데이터 형태에 따라 표출해야해서 체크박스를 포함한 다양한 컨트롤을 사용할 때 문제가 발생 시 아주 곤란했습니다.
  • 텍스트박스의 값을 변경해도 스크롤 발생 시 기존 값으로 다시 표출되는 현상이 발생했습니다.

3. 스크롤을 계속 움직일 경우 프로그램 뻗는 현상 혹은 화면 사라짐 현상 발생

  • 1번과 2번 문제는 binding 포기하더라도 해결할 수 있는 방법이 있었지만 3번 스크롤 문제는 심각하게 다가와서 다시 고민에 빠졌습니다.

🤦‍♀️ DataGrid 스크롤 문제 해결방법 찾기

동적 템플릿 구성에 대한 간단한 테스트 후 기존 소스코드에 다 적용한 상태였기 때문에 마지막 단계에서 방향을 돌려야 한다는 것은 아주 큰 리스크였습니다.

구글링 중 DataGrid 스크롤 문제를 언급하신 TISTORY 블로그를 드디어 찾아내게 됩니다.
무려 2010년에 쓰여진 실버라이트 글이었는데 저에게 큰 도움이 되었습니다.👍

<!-- MainWindow.xaml 파일 -->
<ScrollViewer VerticalScrollBarVisibility="Auto">
   <DataGrid  AutoGenerateColumns="False" Name="grid" CanUserAddRows="False"
              VerticalScrollBarVisibility="Hidden">
   ...
   </DataGrid>
</ScrollViewer>
  • 여기서 중요한 부분은 DataGrid에서 자동으로 생성되는 Scroll을 사용하지 않고 ScrollViewer를 감싸서 DataGrid를 사용해야 한다는 부분이었습니다. ScrollViewerVerticalScrollBarVisibility="Auto", DataGridVerticalScrollBarVisibility="Hidden" 속성이 핵심입니다.

◽ DataGrid 속성 값 적용 후 테스트

  • 아래 위로 스크롤을 움직였을 때 체크박스 해제가 되지 않습니다.

  • 체크박스를 선택 시 연결된 Binding 변수의 set 함수가 호출됩니다.

    하지만 완벽하게 처리되지 않고 여전히 이벤트가 호출되지 않는 현상이 발생했습니다.😢


◽ DataGrid 속성 값 적용 후 보안점

1. 마우스 스크롤 시 ScrollViewer 추가 후 생긴 스크롤 위에서만 마우스 휠로 동작함 (✔해결)

기존에는 DataGrid에서 생긴 스크롤을 사용하여 마우스 휠을 어느 영역에서 하든 위아래 이동이 가능했다면 ScrollViewer를 사용하면 DataGrid 영역 내에서 스크롤 이동이 마우스 휠로 동작하지 않게 됩니다.

  • DataGrid에 전달된 마우스 휠 이벤트가 ScrollViewer로 전달될 수 있도록 PreviewMouseWheel 이벤트를 추가한 후 코드 구현을 합니다. 이렇게 하면 DataGrid 영역 내에서 마우스 휠로 스크롤이 움직이게 됩니다.
<!-- MainWindow.xaml 파일 -->
<ScrollViewer VerticalScrollBarVisibility="Auto" Name="scrollViewer">
   <DataGrid  AutoGenerateColumns="False" Name="grid" CanUserAddRows="False"
              VerticalScrollBarVisibility="Hidden"
              PreviewMouseWheel="DataGrid_PreviewMouseWheel">
   ...
   </DataGrid>
</ScrollViewer>
// MainWindow.xaml.cs
private void DataGrid_PreviewMouseWheel(object sender, MouseWheelEventArgs e){ 
	scrollViewer.ScrollToVerticalOffset(scrollViewer.VerticalOffset - e.Delta / 3);
}

2. DataGrid의 동적 컨트롤 Binding 이벤트 발생하지 않음 (✔해결)

간소화한 소스코드로 테스트 해 본 컨트롤은 TextBox와 CheckBox입니다. 해결방법은 Binding할 때 UpdateSourceTrigger를 추가해 주면 됩니다.

  • CheckBox의 경우 UpdateSourceTrigger 이벤트로 값이 변경될 때마다 감지될 수 있게 PropertyChanged로 설정하였습니다.
  • TextBox의 경우 한글자 입력할 때마다 이벤트가 발생하므로 포커스가 다른 곳으로 이동할 때까지 입력을 받은 후 이벤트를 받고자 LostFocus로 설정하였습니다.
<DataGrid.Columns>
   <DataGridTemplateColumn Header="Name">
   	  <DataGridTemplateColumn.CellTemplate>         
         <DataTemplate>
            ...
			<TextBox Text="{Binding Name, Mode=TwoWay, UpdateSourceTrigger=LostFocus}"/>
            <CheckBox IsChecked="{Binding IsNameChecked, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
            ...
		</DataTemplate>
	</DataGridTemplateColumn.CellTemplate>
</DataGrid.Columns>

3. DataGrid의 Header가 스크롤을 내리는 경우 고정되지 않음 (미해결)

DataGrid를 ScrollViewer로 감싸줬으니 어쩔 수 없는 부분으로 보이긴 하지만 구현하는 입장에서는 아쉬운 부분입니다.

  • 스크롤 내리기 전 Header가 보이는 모습
    스크롤 내리기 전
  • 스크롤 내린 후 Header가 보이지 않는 모습
    스크롤 내린 후

[참조사이트]

0개의 댓글