UI 가상화(Virtualization)이란
올해부터 전산부서로 옮기게 되면서, C#으로 WPF 개발을 하게 되었다. 얼마 전 특정 기능이 되지 않는다는 문의를 받아 해결하던 중, 버그를 하나 발견하게 되었다.
이렇게 화면을 처음 연 상태에서 펼치지 않고 위의 항목을 선택하면? 상식적으로는 펼쳤을 때 아래 것들까지 전부 체크되어야 하는 게 맞지만
이렇게 아래 항목들은 체크가 되지 않는 문제였다. 그런데 더 이상한 건 이렇게 한번 펼치고 접은 다음 다시 체크를 하면
이러면 전부 체크되는 것이었다. 이러니 정신이 나갈 수밖에…
아무튼 열심히 검색해 보던 중, 이 문제가 WPF의 가상화라는 것과 연관된 것을 알 수 있었다.
WPF UI 가상화
WPF에서 List와 Grid 같은 콘트롤은 기본적으로 데이타가 뷰에 바인딩1될 때 현재 UI에 보이는 항목만 뷰에 저장되는 방식을 사용한다.
즉 모델2에 있는 데이타는 100개인데 뷰3에서는 10개 정도밖에 보이지 않으면 뷰에는 10개의 데이타만 있는 것으로 처리되는 것이다.
그럼 이 문제는?
즉 위 문제도 마찬가지로, 맨 처음 화면을 열었을 때는 화면에 Top Level 하나밖에 보이지 않기 때문에 뷰에서는 Top Level 하나만 있는 것으로 간주된다.
그러기에 Top Level을 체크하면 뷰에서 입력을 받아 모델에 반영을 해주는데, 뷰 입장에서는 저 Top Level 하나만 체크된 것이니까 모델에서도 마찬가지로 Top Level에만 처리를 하는 것이다.
해결하기 위해서는?
간단하다. 모델에서 입력을 처리해주면 되는 것이다.
이런식으로 위 화면에서 사용될 TreeViewModel.cs를 만들어 줬다 할 때, 항목의 이름 Name과 상위/하위 항목인 Parent/Children, 체크박스 체크 여부를 다루는 isChecked 이렇게 4개를 만들어 줄 수 있겠다.
그다음 위처럼 XAML을 만들고…
비하인드 코드(xaml.cs)에서 xaml의 TreeView와 TreeViewModel.cs를 연결해준다.
(출처는 https://github.com/benperk/TheBestCSharpProgrammerInTheWorld/tree/master/csharpguitar/TreeView 여기서 가져왔습니다~)
그리고 TreeViewModel.cs의 isChecked는 캡슐화를 해 줘 체크했을 때 하위 항목을 전부 체크해주고(SetIsChecked) 상위 항목의 체크상태를 결정(VerifyCheckedState) 해주도록 한다.
이렇게 되면 뷰에는 가상화 때문에 상위 항목 하나만 있더라도 모델에는 모든 데이타가 있기 때문에 뷰에 없는 데이타도 모델에서 처리되어 정상적으로 보여지게 된다.
또는 xaml에서 Virtualizing(Stack)Panel.IsVirtualizing을 False로 지정하면 이 콘트롤은 가상화를 사용하지 않는다는 의미가 된다. 콘트롤에 따라 VirtualizingPanel이 될 수도, VirtualizingStackPanel이 될 수도 있으니 유의. 다만 이렇게 하면 말 그대로 모든 모델의 데이타를 뷰로 불러온다는 말이므로 데이타가 수백~수천건의 무거운 데이타일 경우 성능 저하가 올 수 있다는 점을 유의해야 한다.
가상화 모드
참고로 콘트롤 속성 중 Virtualizing(Stack)Panel.VirtualizationMode는 가상화를 어떻게 진행할 것인가를 결정하는데, Standard와 Recycling 두 개가 있다.
이 둘의 차이가 무엇인지를 알기 위해 뷰에서 데이타가 담기는 UI 항목을 아이템 콘테이너라고 하는 것을 이해해야 하는데, 그림을 그려 쉽게 설명하자면
이런 리스트 뷰가 있으면 리스트 항목1~4는 모델에서 가져온 데이타이고, 이들을 담는 뷰의 요소(즉 ListView면 ListViewItem)가 아이템 콘테이너인 것이다.
만약 이 ListView가 가상화를 실행중이면 뷰에는 리스트 항목1~4만 올라와질 것이고, 스크롤을 내려 리스트 항목3~6이 표시된다 하면 리스트 항목1~2는 뷰에서 사라지고 5~6이 새로 올라와진다. 하지만 아이템 콘테이너의 운명은 VirtualizationMode가 무엇이냐에 따라 달라지는데 Recycling은 사라지는 항목의 아이템 콘테이너를 재사용한다. 즉
위에서 사라지는 아이템 콘테이너 1과 2를 리스트 항목 5와 6을 담는 곳으로 쓰는 것이다. 말 그대로 재활용~
반면에 Standard는 재활용 그런거 없이 무조건 새 술은 새 부대에 담는다.
따라서 아이템 콘테이너 1과 2는 바이바이 되고 5번과 6번을 새로 만들어서 리스트 항목을 담는다.
Recycling을 사용하면 기존 아이템 콘테이너를 삭제하고 새로 생성하는 작업이 없어지므로 자원을 절약할 수 있다지만 아무래도 안정성은 떨어지기 마련. 기본적으로 가상화 모드는 Recycling으로 지정된다고 한다~