첨부 실행 코드는 나눔고딕코딩 폰트를 사용합니다.
728x90
반응형
728x170

■ DataGrid 클래스에서 대용량 데이터를 바인딩하는 방법을 보여준다.

TestProject.zip
0.01MB

▶ ItemCountEventArgs.cs

using System;

namespace TestProject
{
    /// <summary>
    /// 항목 카운트 이벤트 인자
    /// </summary>
    public class ItemCountEventArgs : EventArgs
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 뷰
        /// </summary>
        private DataGridCollectionView view;

        /// <summary>
        /// 카운트
        /// </summary>
        private int count = 0;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 카운트 - Count

        /// <summary>
        /// 카운트
        /// </summary>
        public int Count
        {
            get => this.count;
            set => this.count = value;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - ItemCountEventArgs(view)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="view">데이터 그리드 컬렉션 뷰</param>
        public ItemCountEventArgs(DataGridCollectionView view)
        {
            this.view = view;
        }

        #endregion
    }
}

 

▶ ItemListEventArgs.cs

using System;
using System.Collections.Generic;

namespace TestProject
{
    /// <summary>
    /// 항목 리스트 이벤트 인자
    /// </summary>
    public class ItemListEventArgs : EventArgs
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Internal

        #region Field

        /// <summary>
        /// 뷰
        /// </summary>
        private DataGridCollectionView view;

        /// <summary>
        /// 시작 인덱스
        /// </summary>
        private int startIndex;

        /// <summary>
        /// 요청 항목 수
        /// </summary>
        private int requestedItemCount;

        /// <summary>
        /// 항목 리스트
        /// </summary>
        private IList<object> itemList;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Internal

        #region 항목 리스트 - ItemList

        /// <summary>
        /// 항목 리스트
        /// </summary>
        internal IList<object> ItemList => this.itemList;

        #endregion

        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 요청 항목 수 - RequestedItemCount

        /// <summary>
        /// 요청 항목 수
        /// </summary>
        public int RequestedItemCount => this.requestedItemCount;

        #endregion
        #region 시작 인덱스 - StartIndex

        /// <summary>
        /// 시작 인덱스
        /// </summary>
        public int StartIndex => this.startIndex;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - ItemListEventArgs(view, startIndex, requestedItemCount)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="view">뷰</param>
        /// <param name="startIndex">시작 인덱스</param>
        /// <param name="requestedItemCount">요청 항목 수</param>
        public ItemListEventArgs(DataGridCollectionView view, int startIndex, int requestedItemCount)
        {
            this.view = view;

            this.startIndex = startIndex;

            this.requestedItemCount = requestedItemCount;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 항목 리스트 설정하기 - SetItemList(itemList)

        /// <summary>
        /// 항목 리스트 설정하기
        /// </summary>
        /// <param name="itemList">항목 리스트</param>
        public void SetItemList(IList<object> itemList)
        {
            this.itemList = itemList;
        }

        #endregion
    }
}

 

▶ DataGridCollectionView.cs

using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Data;

namespace TestProject
{
    /// <summary>
    /// 데이터 그리드 컬렉션 뷰
    /// </summary>
    public class DataGridCollectionView : ListCollectionView
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 항목 수 요청시 이벤트 - ItemCountRequest

        /// <summary>
        /// 항목 수 요청시 이벤트
        /// </summary>
        public event Action<DataGridCollectionView, ItemCountEventArgs> ItemCountRequest = delegate { };

        #endregion
        #region 항목 리스트 요청시 이벤트 - ItemListRequest

        /// <summary>
        /// 항목 리스트 요청시 이벤트
        /// </summary>
        public event Action<DataGridCollectionView, ItemListEventArgs> ItemListRequest = delegate { };

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 페이지 크기
        /// </summary>
        private const int PageSize = 20;

        /// <summary>
        /// 데이터 테이블
        /// </summary>
        private DataTable dataTable;

        /// <summary>
        /// 데이터 행 딕셔너리
        /// </summary>
        Dictionary<int, DataRow> dataRowDictionary = new Dictionary<int, DataRow>();

        /// <summary>
        /// 잠금 여부
        /// </summary>
        private bool isLocked = false;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 카운트 - Count

        /// <summary>
        /// 카운트
        /// </summary>
        public override int Count
        {
            get
            {
                ItemCountEventArgs eventArgs = new ItemCountEventArgs(this);

                ItemCountRequest(this, eventArgs);

                return eventArgs.Count;
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - DataGridCollectionView(list)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="list">리스트</param>
        private DataGridCollectionView(IList list) : base(list)
        {
        }

        #endregion
        #region 생성자 - DataGridCollectionView(dataTable)

        /// <summary>
        /// 생성자
        /// </summary>
        /// <param name="dataTable">데이터 테이블</param>
        public DataGridCollectionView(DataTable dataTable) : this(dataTable.DefaultView)
        {
            this.dataTable = dataTable;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 항목 구하기 - GetItemAt(index)

        /// <summary>
        /// 항목 구하기
        /// </summary>
        /// <param name="index">인덱스</param>
        /// <returns>항목</returns>
        public override object GetItemAt(int index)
        {
            if(!this.dataRowDictionary.ContainsKey(index))
            {
                if(this.isLocked)
                {
                    return this.dataTable.NewRow();
                }

                this.isLocked = true;

                Task.Factory.StartNew
                (
                    () =>
                    {
                        try
                        {
                            int startIndex = index;

                            ItemListEventArgs eventArgs = new ItemListEventArgs(this, startIndex, PageSize);

                            ItemListRequest(this, eventArgs);

                            if(eventArgs.ItemList == null)
                            {
                                return;
                            }

                            int i = 0;

                            foreach(DataRow row in eventArgs.ItemList.OfType<DataRow>())
                            {
                                int newIndex = startIndex + i;

                                this.dataRowDictionary[newIndex] = row;

                                i++;
                            }

                            Action action = () => Refresh();

                            Application.Current.Dispatcher.BeginInvoke(action);
                        }
                        catch(Exception)
                        {
                        }

                        this.isLocked = false;
                    }
                );

                return this.dataTable.NewRow();
            }

            return this.dataRowDictionary[index];
        }

        #endregion
    }
}

 

▶ MainWindowViewModel.cs

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;

namespace TestProject
{
    /// <summary>
    /// 메인 윈도우 뷰 모델
    /// </summary>
    public class MainWindowViewModel : INotifyPropertyChanged
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Event
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 속성 변경시 이벤트 - PropertyChanged

        /// <summary>
        /// 속성 변경시 이벤트
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged = delegate { };

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Field
        ////////////////////////////////////////////////////////////////////////////////////////// Private

        #region Field

        /// <summary>
        /// 카운트
        /// </summary>
        private int count = 10000000;

        /// <summary>
        /// 데이터 테이블
        /// </summary>
        private DataTable dataTable;

        /// <summary>
        /// 난수기
        /// </summary>
        private Random random = new Random();

        /// <summary>
        /// 컬렉션 뷰
        /// </summary>
        private DataGridCollectionView collectionView;

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Property
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 컬렉션 뷰 - CollectionView

        /// <summary>
        /// 컬렉션 뷰
        /// </summary>
        public DataGridCollectionView CollectionView
        {
            get
            {
                return this.collectionView;
            }
            set
            {
                if(this.collectionView != value)
                {
                    this.collectionView = value;

                    FirePropertyChangedEvent(nameof(CollectionView));
                }
            }
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainWindowViewModel()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainWindowViewModel()
        {
            this.dataTable = new DataTable();

            this.dataTable.Columns.Add("Column 1");
            this.dataTable.Columns.Add("Column 2");
            this.dataTable.Columns.Add("Column 3");

            DataGridCollectionView collectionView = new DataGridCollectionView(dataTable);

            collectionView.ItemCountRequest += collectionView_ItemCountRequest;
            collectionView.ItemListRequest  += collectionView_ItemListRequest;

            CollectionView = collectionView;
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////////////////////////// Method
        ////////////////////////////////////////////////////////////////////////////////////////// Private
        //////////////////////////////////////////////////////////////////////////////// Event

        #region 컬렉션 뷰 항목 카운트 요청시 처리하기 - collectionView_ItemCountRequest(sender, e)

        /// <summary>
        /// 컬렉션 뷰 항목 카운트 요청시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void collectionView_ItemCountRequest(DataGridCollectionView sender, ItemCountEventArgs e)
        {
            e.Count = this.count;
        }

        #endregion
        #region 컬렉션 뷰 항목 리스트 요청시 처리하기 - collectionView_ItemListRequest(sender, e)

        /// <summary>
        /// 컬렉션 뷰 항목 리스트 요청시 처리하기
        /// </summary>
        /// <param name="sender">이벤트 발생자</param>
        /// <param name="e">이벤트 인자</param>
        private void collectionView_ItemListRequest(DataGridCollectionView sender, ItemListEventArgs e)
        {
            int startIndex       = e.StartIndex;
            int requestItemCount = e.RequestedItemCount;

            List<object> itemList = new List<object>();

            for(int i = startIndex; i < startIndex + requestItemCount; i++)
            {
                DataRow row = dataTable.NewRow();

                row[0] = i.ToString();
                row[1] = random.Next(1000).ToString();
                row[2] = random.Next(1000).ToString();

                itemList.Add(row);
            }

            e.SetItemList(itemList);
        }

        #endregion

        //////////////////////////////////////////////////////////////////////////////// Function

        #region 속성 변경시 이벤트 발생시키기 - FirePropertyChangedEvent(propertyName)

        /// <summary>
        /// 속성 변경시 이벤트 발생시키기
        /// </summary>
        /// <param name="propertyName">속성명</param>
        private void FirePropertyChangedEvent(string propertyName)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
        }

        #endregion
    }
}

 

▶ MainWindow.xaml

<Window x:Class="TestProject.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="clr-namespace:TestProject"
    Width="800"
    Height="600"
    Title="DataGrid 클래스 : 대용량 데이터 바인딩하기"
    FontFamily="나눔고딕코딩"
    FontSize="16">
    <Window.DataContext>
        <local:MainWindowViewModel />
    </Window.DataContext>
    <Grid>
        <DataGrid
            AutoGenerateColumns="False"
            ItemsSource="{Binding CollectionView, Mode=OneWay}">
            <DataGrid.Columns>
                <DataGridTextColumn Binding="{Binding Path=[0]}" Header="컬럼 1" />
                <DataGridTextColumn Binding="{Binding Path=[1]}" Header="컬럼 2" />
                <DataGridTextColumn Binding="{Binding Path=[2]}" Header="컬럼 3" />
            </DataGrid.Columns>
        </DataGrid>
    </Grid>
</Window>

 

▶ MainWindow.xaml.cs

using System.Windows;

namespace TestProject
{
    /// <summary>
    /// 메인 윈도우
    /// </summary>
    public partial class MainWindow : Window
    {
        //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor
        ////////////////////////////////////////////////////////////////////////////////////////// Public

        #region 생성자 - MainWindow()

        /// <summary>
        /// 생성자
        /// </summary>
        public MainWindow()
        {
            InitializeComponent();
        }

        #endregion
    }
}
728x90
반응형
그리드형(광고전용)
Posted by icodebroker

댓글을 달아 주세요