Winform의 ListView를 사용하다보면 한개 이상의 ListViewItem을 추가할때가 있습니다.

그럴때 BeginUpdate와 EndUpdate를 이용하면 깜빡임을 최소화하고 아이템들이 추가되는 시간을 줄 일 수있습니다.

 

ListView의 Item 추가하는 로직은 잘 모르겠지만 제 생각에는 아래와 같은 구조일 것 같습니다.

 

 

         

/// <summary>

        /// 기존 System.Windows.Forms.ListViewItem 컬렉션에 추가합니다.

        /// </summary>

        /// <param name="?"></param>

        public void Add(ListViewItem value)

        {

            //Dowork..

 

            //BeginUpdate Count 0 아니라면 컨트롤을 다시 그립니다.

            if(this.beginUpdateCount!=0)

                this.Invalidate();

        }

 

 

MSDN에 ListVIew BeginUpdate에 대한 설명에는 아래와 같이 나와있습니다.

 

BeginUpdate 를 두 번 이상 호출하는 경우 EndUpdate를 같은 횟수만큼 호출해야 합니다. EndUpdate 를 마지막으로 호출한 후에 ListView가 다시 그려집니다.이렇게 하지 않으면 BeginUpdate를 여러 번 호출해도 효과가 없습니다.

참고 : http://msdn.microsoft.com/ko-kr/library/60dc8hf5(v=vs.100).aspx

 

즉, BeginUpdate를 호출하면 ListView 컨트롤을 다시 그리지 않습니다.

아이템을 추가하기 전에 BeginUpdate 메서드를 호출하여 ListView를 다시 그리지 않게 막은 후

아이템을 모두 추가한 후에 EndUpdate 메서드를 호출하여 ListView를 다시그려주게되면 성능이 향상하게 됩니다.

 

아래의 테스트 결과 이미지를 확인해보시면 그냥 Item을 추가한 경우와  BeginUpdate, EndUpdate 메서드를 호출할 때의 성능 차이를 확인 하실수 있습니다.

약 2배의 성능이 향상 되었습니다. 직접 테스트를 진행해보시면 깜빡임도 줄어든것을 확인 하실 수 있습니다.

(ListViewItem 500개 추가할때의 테스트)

 

[이미지 1] 테스트 결과

 

 

 

 

 

 

 

 

 

코드 :

 

 

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Linq;

using System.Text;

using System.Windows.Forms;

using System.Diagnostics;

 

namespace TestPerformance

{

    public partial class TestListViewPerformance : Form,ITest

    {

        const string TXT_NOT_USED_UPDATE = "Not call Update mehthod : {0}";

        const string TXT_USED_UPDATE = "Call Update mehthod : {0}";

 

        public TestListViewPerformance()

        {

            InitializeComponent();

        }

 

        /// <summary>

        /// ListViewItem 추가합니다.

        /// </summary>

        /// <param name="isUseUpdateMethod">BeginUpdate, EndUpdate 호출 여부</param>

        /// <param name="lvis">ListViewItem 배열</param>

        private void AddListViewItem(bool isUseUpdateMethod, ListViewItem[] lvis)

        {

            if (isUseUpdateMethod)

            {

                this.lv_test.BeginUpdate();  

            }

 

           

foreach (var item in lvis)

            {

                this.lv_test.Items.Add(item);

            }

            // AddRange 내부적으로 BeginUpdate EndUpdate 호출하는 같습니다.

            //this.lv_test.Items.AddRange(lvis);

 

            if (isUseUpdateMethod)

            {

                this.lv_test.EndUpdate();

            }

        }

       

 

        /// <summary>

        /// BeginUpdate, EndUpdate 사용하지 않는 로직을 수행합니다.

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btn_notUseUpdate_Click(object sender, EventArgs e)

        {

            Stopwatch sw = new Stopwatch();

 

            this.lv_test.Items.Clear();

            sw.Start();

 

            this.AddListViewItem(false, this.CreateTestListViewItems());

 

            sw.Stop();

           

            Console.WriteLine(string.Format(TXT_NOT_USED_UPDATE,sw.Elapsed.ToString()));

            Debug.WriteLine(string.Format(TXT_NOT_USED_UPDATE, sw.Elapsed.ToString()));

        }

 

        /// <summary>

        /// BeginUpdate, EndUpdate 사용하는 로직을 수행합니다.

        /// </summary>

        /// <param name="sender"></param>

        /// <param name="e"></param>

        private void btn_useUpdate_Click(object sender, EventArgs e)

        {

            Stopwatch sw = new Stopwatch();

 

            this.lv_test.Items.Clear();

            sw.Start();

 

            this.AddListViewItem(true, this.CreateTestListViewItems());

 

            sw.Stop();

 

            Console.WriteLine(string.Format(TXT_USED_UPDATE, sw.Elapsed.ToString()));

            Debug.WriteLine(string.Format(TXT_USED_UPDATE, sw.Elapsed.ToString()));

        }

 

        /// <summary>

        /// Test ListViewItem 생성합니다.

        /// </summary>

        /// <returns></returns>

        private ListViewItem[] CreateTestListViewItems()

        {

            ListViewItem[] lvis = new ListViewItem[500];

 

            for (int i = 0; i < lvis.Length; i++)

            {

                lvis[i] = new ListViewItem(i.ToString());

                for (int j = 1; j < this.lv_test.Columns.Count; j++)

                {

                    lvis[i].SubItems.Add(i.ToString());

                }

            }

 

            return lvis;

        }

 

        public void StartTest()

        {

            throw new NotImplementedException();

        }

    }

}

  

 

+ Recent posts