728x90
반응형
728x170
■ DataGrid 클래스에서 대용량 데이터를 바인딩하는 방법을 보여준다.
▶ 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
반응형
그리드형(광고전용)
'C# > WPF' 카테고리의 다른 글
[C#/WPF] VirtualizingStackPanel 클래스 : IsVirtualizing/VirtualizationMode 속성을 사용해 대용량 데이터 바인딩하기 (0) | 2021.12.31 |
---|---|
[C#/WPF] Popup 클래스 : 다른 엘리먼트 위에 엘리먼트를 오버레이 배치하기 (0) | 2021.12.31 |
[C#/WPF] HwndHost 클래스 : WPF 윈도우 내부에서 메모장 윈도우 호스팅하기 (0) | 2021.12.31 |
[C#/WPF] 3D 애니메이션 시계 사용하기 (절전 모드 방지 기능 추가) (0) | 2021.11.17 |
[C#/WPF] DataGrid 클래스 : 데이터 업데이트 성능 측정하기 (0) | 2021.10.22 |
[C#/WPF/.NETCORE] FaceDetector 클래스 : DetectFacesAsync 메소드를 사용해 얼굴 탐지하기 (0) | 2021.09.23 |
[C#/WPF/.NETCORE] 누겟 설치 : Microsoft.Windows.SDK.Contracts (0) | 2021.09.23 |
[C#/WPF/.NETCORE] BitmapImage 클래스 : WINFORM Bitmap 객체에서 비트맵 이미지 구하기 (0) | 2021.09.23 |
[C#/WPF/.NETCORE] IValueConverter 인터페이스 : 비트맵→비트맵 소스 변환자 사용하기 (0) | 2021.09.23 |
[C#/WPF] ICommand 인터페이스 : 릴레이 명령 사용하기 (0) | 2021.09.23 |
댓글을 달아 주세요