■ PLinqInstantFeedbackDataSource 엘리먼트를 사용하는 방법을 보여준다.
▶ Data.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 |
using System; using System.Collections.Generic; namespace HowToParallelizeDataIntensiveOperationsOnInMemoryData { /// <summary> /// 데이터 /// </summary> public static class Data { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 고객 리스트 /// </summary> private static List<string> customerList; /// <summary> /// 제품 리스트 /// </summary> private static List<KeyValuePair<string, decimal>> productList; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Public #region 고객 리스트 - CustomerList /// <summary> /// 고객 리스트 /// </summary> public static List<string> CustomerList { get { if(this.customerList == null) { this.customerList = new List<string>(); this.customerList.AddRange ( new string[] { "Maria Anders" , "Ana Trujillo" , "Antonio Moreno" , "Thomas Hardy" , "Christina Berglund", "Hanna Moos" , "Frédérique Citeaux" , "Martín Sommer" , "Laurence Lebihan" , "Elizabeth Lincoln" , "Victoria Ashworth" , "Patricio Simpson" , "Francisco Chang" , "Yang Wang" , "Pedro Afonso" , "Elizabeth Brown" , "Sven Ottlieb" , "Janine Labrune" , "Ann Devon" , "Roland Mendel" , "Aria Cruz" , "Diego Roel" , "Martine Rancé" , "Maria Larsson" , "Peter Franken" , "Carine Schmitt" , "Paolo Accorti" , "Lino Rodriguez " , "Eduardo Saavedra" , "José Pedro Freyre" , "André Fonseca" , "Howard Snyder" , "Manuel Pereira" , "Mario Pontes" , "Carlos Hernández" , "Yoshi Latimer" , "Patricia McKenna" , "Helen Bennett" , "Philip Cramer" , "Daniel Tonini" , "Annette Roulet" , "Yoshi Tannamuri" , "John Steel" , "Renate Messner" , "Jaime Yorres" , "Carlos González" , "Felipe Izquierdo" , "Fran Wilson" , "Giovanni Rovelli" , "Catherine Dewey" , "Jean Fresnière" , "Alexander Feuer" , "Simon Crowther" , "Yvonne Moncada" , "Rene Phillips" , "Henriette Pfalzheim" , "Marie Bertrand" , "Guillermo Fernández" , "Georg Pipps" , "Isabel de Castro" , "Bernardo Batista" , "Lúcia Carvalho" , "Horst Kloss" , "Sergio Gutiérrez" , "Paula Wilson" , "Maurizio Moroni" , "Janete Limeira" ,"Michael Holz" , "Alejandra Camino" , "Jonas Bergulfsen" , "Jose Pavarotti" , "Hari Kumar" , "Jytte Petersen" , "Dominique Perrier" , "Art Braunschweiger", "Pascale Cartrain" , "Liz Nixon" , "Liu Wong" , "Karin Josephs" , "Miguel Angel Paolino", "Anabela Domingues" , "Helvetius Nagy" , "Palle Ibsen" , "Mary Saveley" , "Paul Henriot" , "Rita Müller" , "Pirkko Koskitalo" , "Paula Parente" , "Karl Jablonski" , "Matti Karttunen" , "Zbyszek Piestrzeniewicz" } ); } return this.customerList; } } #endregion #region 제품 리스트 - ProductList /// <summary> /// 제품 리스트 /// </summary> public static List<KeyValuePair<string, decimal>> ProductList { get { if(this.productList == null) { this.productList = new List<KeyValuePair<string, decimal>>(); this.productList.Add(new KeyValuePair<string,decimal>("Chai" , 18.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Chang" , 19.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Aniseed Syrup" , 10.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Chef Anton's Cajun Seasoning" , 22.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Chef Anton's Gumbo Mix" , 21.35m )); this.productList.Add(new KeyValuePair<string,decimal>("Grandma's Boysenberry Spread" , 25.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Uncle Bob's Organic Dried Pears" , 30.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Northwoods Cranberry Sauce" , 40.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Mishi Kobe Niku" , 97.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Ikura" , 31.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Queso Cabrales" , 21.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Queso Manchego La Pastora" , 38.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Konbu" , 6.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Tofu" , 23.25m )); this.productList.Add(new KeyValuePair<string,decimal>("Genen Shouyu" , 15.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Pavlova" , 17.45m )); this.productList.Add(new KeyValuePair<string,decimal>("Alice Mutton" , 39.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Carnarvon Tigers" , 62.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Teatime Chocolate Biscuits" , 9.2m )); this.productList.Add(new KeyValuePair<string,decimal>("Sir Rodney's Marmalade" , 81.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Sir Rodney's Scones" , 10.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Gustaf's Knäckebröd" , 21.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Tunnbröd" , 9.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Guaraná Fantástica" , 4.5m )); this.productList.Add(new KeyValuePair<string,decimal>("NuNuCa Nuß-Nougat-Creme" , 14.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Gumbär Gummibärchen" , 31.23m )); this.productList.Add(new KeyValuePair<string,decimal>("Schoggi Schokolade" , 43.9m )); this.productList.Add(new KeyValuePair<string,decimal>("Rössle Sauerkraut" , 45.6m )); this.productList.Add(new KeyValuePair<string,decimal>("Thüringer Rostbratwurst" , 123.79m)); this.productList.Add(new KeyValuePair<string,decimal>("Nord-Ost Matjeshering" , 25.89m )); this.productList.Add(new KeyValuePair<string,decimal>("Gorgonzola Telino" , 12.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Mascarpone Fabioli" , 32.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Geitost" , 2.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Sasquatch Ale" , 14.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Steeleye Stout" , 18.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Inlagd Sill" , 19.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Gravad lax" , 26.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Côte de Blaye" , 263.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Chartreuse verte" , 18.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Boston Crab Meat" , 18.4m )); this.productList.Add(new KeyValuePair<string,decimal>("Jack's New England Clam Chowder" , 9.65m )); this.productList.Add(new KeyValuePair<string,decimal>("Singaporean Hokkien Fried Mee" , 14.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Ipoh Coffee" , 46.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Gula Malacca" , 19.45m )); this.productList.Add(new KeyValuePair<string,decimal>("Røgede sild" , 9.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Spegesild" , 12.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Zaanse koeken" , 9.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Chocolade" , 12.75m )); this.productList.Add(new KeyValuePair<string,decimal>("Maxilaku" , 20.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Valkoinen suklaa" , 16.25m )); this.productList.Add(new KeyValuePair<string,decimal>("Manjimup Dried Apples" , 53.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Filo Mix" , 7.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Perth Pasties" , 32.8m )); this.productList.Add(new KeyValuePair<string,decimal>("Tourtière" , 7.45m )); this.productList.Add(new KeyValuePair<string,decimal>("Pâté chinois" , 24.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Gnocchi di nonna Alice" , 38.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Ravioli Angelo" , 19.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Escargots de Bourgogne" , 13.25m )); this.productList.Add(new KeyValuePair<string,decimal>("Raclette Courdavault" , 55.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Camembert Pierrot" , 34.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Sirop d'érable" , 28.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Tarte au sucre" , 49.3m )); this.productList.Add(new KeyValuePair<string,decimal>("Vegie-spread" , 43.9m )); this.productList.Add(new KeyValuePair<string,decimal>("Wimmers gute Semmelknödel" , 33.25m )); this.productList.Add(new KeyValuePair<string,decimal>("Louisiana Fiery Hot Pepper Sauce", 21.05m )); this.productList.Add(new KeyValuePair<string,decimal>("Louisiana Hot Spiced Okra" , 17.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Laughing Lumberjack Lager" , 14.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Scottish Longbreads" , 12.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Gudbrandsdalsost" , 36.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Outback Lager" , 15.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Fløtemysost" , 21.5m )); this.productList.Add(new KeyValuePair<string,decimal>("Mozzarella di Giovanni" , 34.8m )); this.productList.Add(new KeyValuePair<string,decimal>("Röd Kaviar" , 15.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Longlife Tofu" , 10.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Rhönbräu Klosterbier" , 7.75m )); this.productList.Add(new KeyValuePair<string,decimal>("Lakkalikööri" , 18.0m )); this.productList.Add(new KeyValuePair<string,decimal>("Original Frankfurter grüne Soße" , 13.0m )); } return this.productList; } } #endregion } } |
▶ OrderData.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
using System; namespace HowToParallelizeDataIntensiveOperationsOnInMemoryData { /// <summary> /// 주문 데이터 /// </summary> public class OrderData { //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 주문 ID - OrderID /// <summary> /// 주문 ID /// </summary> public int OrderID { get; set; } #endregion #region 고객명 - CustomerName /// <summary> /// 고객명 /// </summary> public string CustomerName { get; set; } #endregion #region 주문일 - OrderDate /// <summary> /// 주문일 /// </summary> public DateTime OrderDate { get; set; } #endregion #region 제품명 - ProductName /// <summary> /// 제품명 /// </summary> public string ProductName { get; set; } #endregion #region 가격 - Price /// <summary> /// 가격 /// </summary> public decimal Price { get; set; } #endregion #region 수량 - Quantity /// <summary> /// 수량 /// </summary> public int Quantity { get; set; } #endregion } } |
▶ OrderDataListSource.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; namespace HowToParallelizeDataIntensiveOperationsOnInMemoryData { /// <summary> /// 주문 데이터 리스트 소스 /// </summary> public class OrderDataListSource : IListSource { //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 잠금자 /// </summary> private static object locker = new object(); #endregion ////////////////////////////////////////////////////////////////////////////////////////// Static //////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 주문 데이터 리스트 /// </summary> private List<OrderData> orderDataList; /// <summary> /// 카운트 /// </summary> private int count = 0; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 리스트 컬렉션 포함 여부 - ContainsListCollection /// <summary> /// 리스트 컬렉션 포함 여부 /// </summary> public bool ContainsListCollection { get { return false; } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - OrderDataListSource(count) /// <summary> /// 생성자 /// </summary> /// <param name="count">카운트</param> public OrderDataListSource(int count) { this.count = count; } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Method ////////////////////////////////////////////////////////////////////////////////////////// Public #region 리스트 구하기 - GetList() /// <summary> /// 리스트 구하기 /// </summary> /// <returns>리스트</returns> public IList GetList() { if(this.orderDataList == null) { lock(this.locker) { if(this.orderDataList == null) { GenerateOrderData(); } } } return this.orderDataList; } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Private #region 주문 데이터 생성하기 - GenerateOrderData() /// <summary> /// 주문 데이터 생성하기 /// </summary> private void GenerateOrderData() { this.orderDataList = new List<OrderData>(this.count); Random random = new Random(); int customerCount = Data.CustomerList.Count; int productCount = Data.ProductList.Count; for(int i = 0; i < this.count; i++) { OrderData orderData = new OrderData(); orderData.OrderID = i + 1; orderData.CustomerName = Data.CustomerList[pRandom.Next(customerCount)]; orderData.OrderDate = DateTime.Today.Subtract(TimeSpan.FromDays(random.Next(180))); KeyValuePair<string, decimal> productKeyValuePair = Data.ProductList[random.Next(productCount)]; orderData.ProductName = productKeyValuePair.Key; orderData.Price = productKeyValuePair.Value; orderData.Quantity = random.Next(200) + 1; this.orderDataList.Add(orderData); } } #endregion } } |
▶ ViewModel.cs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 |
using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; namespace HowToParallelizeDataIntensiveOperationsOnInMemoryData { /// <summary> /// 뷰 모델 /// </summary> public class ViewModel : INotifyPropertyChanged { //////////////////////////////////////////////////////////////////////////////////////////////////// Event ////////////////////////////////////////////////////////////////////////////////////////// Public #region 속성 변경시 - PropertyChanged /// <summary> /// 속성 변경시 /// </summary> public event PropertyChangedEventHandler PropertyChanged; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Field ////////////////////////////////////////////////////////////////////////////////////////// Private #region Field /// <summary> /// 주문 데이터 리스트 소스 /// </summary> private OrderDataListSource orderDataListSource; #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Property ////////////////////////////////////////////////////////////////////////////////////////// Public #region 주문 데이터 리스트 소스 - OrderDataListSource /// <summary> /// 주문 데이터 리스트 소스 /// </summary> public OrderDataListSource OrderDataListSource { get { return this.orderDataListSource; } set { if(this.orderDataListSource == value) { return; } this.orderDataListSource = value; OnPropertyChanged("ListSource"); } } #endregion //////////////////////////////////////////////////////////////////////////////////////////////////// Constructor ////////////////////////////////////////////////////////////////////////////////////////// Public #region 생성자 - ViewModel() /// <summary> /// 생성자 /// </summary> public ViewModel() { OrderDataListSource = new OrderDataListSource(1000000); } #endregion ////////////////////////////////////////////////////////////////////////////////////////// Protected #region 속성 변경시 처리하기 - OnPropertyChanged(propertyName) /// <summary> /// 속성 변경시 처리하기 /// </summary> /// <param name="propertyName">속성명</param> protected virtual void OnPropertyChanged(string propertyName) { if(PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); } } #endregion } } |
▶ MainWindow.xaml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
<Window x:Class="HowToParallelizeDataIntensiveOperationsOnInMemoryData.MainWindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:dx="http://schemas.devexpress.com/winfx/2008/xaml/core" xmlns:dxe="http://schemas.devexpress.com/winfx/2008/xaml/editors" xmlns:dxg="http://schemas.devexpress.com/winfx/2008/xaml/grid" xmlns:local="clr-namespace:HowToParallelizeDataIntensiveOperationsOnInMemoryData" Width="800" Height="600" Title="MainWindow"> <Window.DataContext> <local:ViewModel /> </Window.DataContext> <Grid> <dx:PLinqInstantFeedbackDataSource x:Name="pLinqInstantFeedbackDataSource" ListSource="{Binding Path=OrderDataListSource}" /> <dxg:GridControl x:Name="gridControl" ItemsSource="{Binding ElementName=pLinqInstantFeedbackDataSource, Path=Data}"> <dxg:GridControl.Columns> <dxg:GridColumn x:Name="idGridColumn" FieldName="OrderID" Header="ID" Width="60" MinWidth="60" AllowColumnFiltering="False" AllowGrouping="False" /> <dxg:GridColumn x:Name="customerNameGridColumn" FieldName="CustomerName" Width="200" /> <dxg:GridColumn x:Name="orderDateGridColumn" FieldName="OrderDate" Width="100" AllowColumnFiltering="False"> <dxg:GridColumn.EditSettings> <dxe:DateEditSettings DisplayFormat="d" /> </dxg:GridColumn.EditSettings> </dxg:GridColumn> <dxg:GridColumn x:Name="productNameGridColumn" FieldName="ProductName" Width="200" /> <dxg:GridColumn x:Name="priceGridColumn" FieldName="Price" Width="60" /> <dxg:GridColumn x:Name="quantityGridColumn" FieldName="Quantity" Width="60" /> </dxg:GridControl.Columns> <dxg:GridControl.View> <dxg:TableView AutoWidth="False" ShowTotalSummary="False" RowAnimationKind="Opacity" /> </dxg:GridControl.View> </dxg:GridControl> </Grid> <i:Interaction.Triggers> <i:EventTrigger EventName="Closed"> <i:InvokeCommandAction Command="{Binding ElementName=pLinqInstantFeedbackDataSource, Path=DisposeCommand}" /> </i:EventTrigger> </i:Interaction.Triggers> </Window> |