티스토리 뷰

반응형

2022.04.11 - [WPF .NET] - 대용량 데이터처리시 발생되는 UI Freeze 문제 해결 part1

 

이전 포스트에서 Yield를 이용해서 데이터를 조금씩 읽어서 처리할 수 있는 방법을 살펴보았습니다.

하지만, 여전히 UI Freeze 문제를 해결할 수는 없었는데요, 음... 오늘은 UI 출력 방법을 바꾸어 보도록 하겠습니다.

 

1. foreeach를 이용해서 데이터를 하나씩 그냥 추가하면 않될까?

yield return을 이용해서 데이터를 조금씩 가지고 올 수 있으면, foreach를 이용해서 가져온 데이터를 하나씩 ListBox에 넣는다면? ItemsSource는 데이터를 하나씩 넣을 수 없는데? ObservableCollection을 사용해?

여러가지 생각들이 꼬리에 꼬리를 물면서 저를 괴롭히네요..

ObservableCollection을 이용해서 넣는건 대용량 데이터 처리에는 성능이 매우 떨어지기 때문에 사용이 꺼려지는데.. 그럼 어떻게 처리를 해야할지 고민고민~

2. Items 프로퍼티 사용하기

ItemsSource 속성에 대한 설명을 살펴보던 중 Items 프로퍼티에 대한 설명이 함께나오는 것을 보고, Items와 ItemsSource 프로퍼티에 대해서 검색을 진행해보니, Items 프로퍼티를 사용하지 못할 이유가 없다는 것을 알게되었습니다. 물론 Items 프로퍼티는 바인딩이 불가능합니다만, 그건 해결가능하기 때문에 문제가 없었습니다.

아래 코드는 ListBox의 Items 프로퍼티에 model을 하나씩 추가하도록 수정했으며, UI Freeze 부분 해결을 위해서 await Task.Delay(1);을 추가했습니다.

        private async void Button_Click(object sender, RoutedEventArgs e)
        {
            var dialog = new OpenFileDialog
            {
                Filter = "All files (*.*)|*.*"
            };
            var result = dialog.ShowDialog();
            if (result == false)
            {
                return;
            }
            var fileName = dialog.FileName;
            if (string.IsNullOrEmpty(fileName))
            {
                return;
            }
            var models = GetModels(fileName);
            //모델을 한번에 ItemsSource에 연결
            //listBox.ItemsSource = models;
            foreach (var model in models)
            {
                await Task.Delay(1);
                listBox.Items.Add(model);
            }
        }

3. 세번째 화면 결과

UI Freeze가 걸리지 않고, 부드럽게 움직이며, 데이터가 추가되는 모습을 확인할 수있습니다.

그런데, 데이터 하나 불러올때마다 1 밀리세컨트씩 Delay를 발생시키니 모든 데이터를 불러오는데, 너무 오래 걸리는 것 같습니다. 또한, 이 방법은 전체 카운트를 구할 수가 없습니다. ^^;;

 

아래와 같이 수정했습니다. 1000번에 1번씩만 Deley(1)을 실행합니다.

            int count = 0;
            //total count는 구할수 없음
            foreach (var model in models)
            {
                count++;
                if (count % 1000 == 0)
                {
                    CountTextBlock.Text = count.ToString("N0");
                    await Task.Delay(1);
                }
                listBox.Items.Add(model);
            }
            CountTextBlock.Text = count.ToString("N0");

개선 버전 화면

화면 UI Freeze 문제 해결되었고, 데이터 조회하는 속도도 이전에 비해서는 빠르게 실행 됩니다. 상단에 현재 조회된 데이터 수를 표시하기 때문에, 지루함(?)을 느끼지는 않겠죠?

최종 결과 화면

Memory : 8.4GB

로딩시간 : 약 2분30초

 

ItemsSource에 넣는것보다 약 2.5배정도의 시간이 더 소요되지만, UI에 여러가지 정보를 출력해서 실제, 사용자가 느끼는 지루함은 덜 할 것이라고 생각됩니다.

 

다음 part3에서는 MVVM pattern에서 사용하는 방법을 알아보도록 하겠습니다.

4. 소스

WpfTest/LargeFileReadSample at master · kaki104/WpfTest (github.com)

 

GitHub - kaki104/WpfTest

Contribute to kaki104/WpfTest development by creating an account on GitHub.

github.com

 

반응형
댓글