├── .gitignore ├── .tfignore ├── DVFilterSort.sln ├── DVFilterSort ├── App.xaml ├── App.xaml.cs ├── Converter.cs ├── CustomerProvider.cs ├── Customers.dbml ├── Customers.dbml.layout ├── Customers.designer.cs ├── CustomersDataSet.Designer.cs ├── CustomersDataSet.xsc ├── CustomersDataSet.xsd ├── CustomersDataSet.xss ├── DVFilterSort.csproj ├── DataGridHelper.cs ├── MainWindow.xaml ├── MainWindow.xaml.cs ├── Properties │ ├── AssemblyInfo.cs │ ├── Resources.Designer.cs │ ├── Resources.resx │ ├── Settings.Designer.cs │ └── Settings.settings └── app.config ├── DataVirtualization ├── AsyncVirtualizingCollection.cs ├── DataPage.cs ├── DataVirtualization.csproj ├── DataWrapper.cs ├── IItemsProvider.cs ├── Properties │ └── AssemblyInfo.cs └── VirtualizingCollection.cs ├── README.md └── ReusableControls ├── DateRangePicker.xaml ├── DateRangePicker.xaml.cs ├── Properties ├── AssemblyInfo.cs ├── Resources.Designer.cs ├── Resources.resx ├── Settings.Designer.cs └── Settings.settings └── ReusableControls.csproj /.gitignore: -------------------------------------------------------------------------------- 1 | # Build Folders (you can keep bin if you'd like, to store dlls and pdbs) 2 | [Bb]in/ 3 | [Oo]bj/ 4 | 5 | # mstest test results 6 | TestResults 7 | 8 | ## Ignore Visual Studio temporary files, build results, and 9 | ## files generated by popular Visual Studio add-ons. 10 | 11 | # User-specific files 12 | *.suo 13 | *.user 14 | *.sln.docstates 15 | 16 | # Build results 17 | [Dd]ebug/ 18 | [Rr]elease/ 19 | x64/ 20 | *_i.c 21 | *_p.c 22 | *.ilk 23 | *.meta 24 | *.obj 25 | *.pch 26 | *.pdb 27 | *.pgc 28 | *.pgd 29 | *.rsp 30 | *.sbr 31 | *.tlb 32 | *.tli 33 | *.tlh 34 | *.tmp 35 | *.log 36 | *.vspscc 37 | *.vssscc 38 | .builds 39 | 40 | # Visual C++ cache files 41 | ipch/ 42 | *.aps 43 | *.ncb 44 | *.opensdf 45 | *.sdf 46 | 47 | # Visual Studio profiler 48 | *.psess 49 | *.vsp 50 | *.vspx 51 | 52 | # Guidance Automation Toolkit 53 | *.gpState 54 | 55 | # ReSharper is a .NET coding add-in 56 | _ReSharper* 57 | 58 | # NCrunch 59 | *.ncrunch* 60 | .*crunch*.local.xml 61 | 62 | # Installshield output folder 63 | [Ee]xpress 64 | 65 | # DocProject is a documentation generator add-in 66 | DocProject/buildhelp/ 67 | DocProject/Help/*.HxT 68 | DocProject/Help/*.HxC 69 | DocProject/Help/*.hhc 70 | DocProject/Help/*.hhk 71 | DocProject/Help/*.hhp 72 | DocProject/Help/Html2 73 | DocProject/Help/html 74 | 75 | # Click-Once directory 76 | publish 77 | 78 | # Publish Web Output 79 | *.Publish.xml 80 | 81 | # NuGet Packages Directory 82 | packages 83 | 84 | # Windows Azure Build Output 85 | csx 86 | *.build.csdef 87 | 88 | # Windows Store app package directory 89 | AppPackages/ 90 | 91 | # Others 92 | [Bb]in 93 | [Oo]bj 94 | sql 95 | TestResults 96 | [Tt]est[Rr]esult* 97 | *.Cache 98 | ClientBin 99 | [Ss]tyle[Cc]op.* 100 | ~$* 101 | *.dbmdl 102 | Generated_Code #added for RIA/Silverlight projects 103 | 104 | # Backup & report files from converting an old project file to a newer 105 | # Visual Studio version. Backup files are not needed, because we have git ;-) 106 | _UpgradeReport_Files/ 107 | Backup*/ 108 | UpgradeLog*.XML 109 | -------------------------------------------------------------------------------- /.tfignore: -------------------------------------------------------------------------------- 1 | \.git -------------------------------------------------------------------------------- /DVFilterSort.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 11.00 3 | # Visual Studio 2010 4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DVFilterSort", "DVFilterSort\DVFilterSort.csproj", "{EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}" 5 | EndProject 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ReusableControls", "ReusableControls\ReusableControls.csproj", "{37EC527A-D370-4643-A4A5-F585D18244D1}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataVirtualization", "DataVirtualization\DataVirtualization.csproj", "{F0551328-4699-43B6-949E-9BDABF89FC1E}" 9 | EndProject 10 | Global 11 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 12 | Debug|Any CPU = Debug|Any CPU 13 | Debug|Mixed Platforms = Debug|Mixed Platforms 14 | Debug|x86 = Debug|x86 15 | Release|Any CPU = Release|Any CPU 16 | Release|Mixed Platforms = Release|Mixed Platforms 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Debug|Any CPU.ActiveCfg = Debug|x86 21 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Debug|Mixed Platforms.ActiveCfg = Debug|x86 22 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Debug|Mixed Platforms.Build.0 = Debug|x86 23 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Debug|x86.ActiveCfg = Debug|x86 24 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Debug|x86.Build.0 = Debug|x86 25 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Release|Any CPU.ActiveCfg = Release|x86 26 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Release|Mixed Platforms.ActiveCfg = Release|x86 27 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Release|Mixed Platforms.Build.0 = Release|x86 28 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Release|x86.ActiveCfg = Release|x86 29 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A}.Release|x86.Build.0 = Release|x86 30 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 31 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Debug|Any CPU.Build.0 = Debug|Any CPU 32 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 33 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 34 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Debug|x86.ActiveCfg = Debug|Any CPU 35 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Release|Any CPU.ActiveCfg = Release|Any CPU 36 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Release|Any CPU.Build.0 = Release|Any CPU 37 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 38 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Release|Mixed Platforms.Build.0 = Release|Any CPU 39 | {37EC527A-D370-4643-A4A5-F585D18244D1}.Release|x86.ActiveCfg = Release|Any CPU 40 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Debug|Mixed Platforms.ActiveCfg = Debug|Any CPU 43 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Debug|Mixed Platforms.Build.0 = Debug|Any CPU 44 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Debug|x86.ActiveCfg = Debug|Any CPU 45 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Release|Any CPU.ActiveCfg = Release|Any CPU 46 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Release|Any CPU.Build.0 = Release|Any CPU 47 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Release|Mixed Platforms.ActiveCfg = Release|Any CPU 48 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Release|Mixed Platforms.Build.0 = Release|Any CPU 49 | {F0551328-4699-43B6-949E-9BDABF89FC1E}.Release|x86.ActiveCfg = Release|Any CPU 50 | EndGlobalSection 51 | GlobalSection(SolutionProperties) = preSolution 52 | HideSolutionNode = FALSE 53 | EndGlobalSection 54 | EndGlobal 55 | -------------------------------------------------------------------------------- /DVFilterSort/App.xaml: -------------------------------------------------------------------------------- 1 |  5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /DVFilterSort/App.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Data; 5 | using System.Linq; 6 | using System.Windows; 7 | 8 | namespace DVFilterSort 9 | { 10 | /// 11 | /// Interaction logic for App.xaml 12 | /// 13 | public partial class App : Application 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /DVFilterSort/Converter.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows.Data; 6 | using System.Globalization; 7 | 8 | namespace DVFilterSort 9 | { 10 | public class DateConverter : IValueConverter 11 | { 12 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 13 | { 14 | DateTime date = (DateTime)value; 15 | return String.Format("{0:d}", date); 16 | } 17 | 18 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 19 | { 20 | throw new NotImplementedException(); 21 | } 22 | } 23 | 24 | public class MoneyConverter : IValueConverter 25 | { 26 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 27 | { 28 | double money = (double)value; 29 | return String.Format("{0:c}", money); 30 | } 31 | 32 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 33 | { 34 | throw new NotImplementedException(); 35 | } 36 | } 37 | 38 | public class RegionConverter : IValueConverter 39 | { 40 | public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 41 | { 42 | int intValue; 43 | bool parsed = Int32.TryParse(value.ToString(), out intValue); 44 | if (parsed) 45 | { 46 | USRegion region = (USRegion)(int)value; 47 | return region.ToString(); 48 | } 49 | return ""; 50 | } 51 | 52 | public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) 53 | { 54 | throw new NotImplementedException(); 55 | } 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /DVFilterSort/CustomerProvider.cs: -------------------------------------------------------------------------------- 1 | #region 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Threading; 7 | using DataVirtualization; 8 | 9 | #endregion 10 | 11 | namespace DVFilterSort 12 | { 13 | public class CustomerProvider : IItemsProvider 14 | { 15 | private readonly List _customers; 16 | private readonly DateTime? _dateFrom; 17 | private readonly DateTime? _dateTo; 18 | private readonly string _sortField; 19 | private int _count; 20 | 21 | public CustomerProvider() 22 | { 23 | _dateFrom = DateTime.Today.AddYears(-100); 24 | _dateTo = DateTime.Today.AddYears(100); 25 | _sortField = "CustomerSince DESC"; 26 | 27 | _customers = new List(); 28 | for (int i = 0; i < 10000; i++) 29 | { 30 | _customers.Add(new Customer 31 | { 32 | AmountPaidInternationalCalls = i%100, 33 | AmountPaidLocalCalls = i%100, 34 | AmountPaidNationalCalls = i%100, 35 | CustomerSince = _dateFrom.Value.AddDays(i), 36 | FirstName = string.Format("Customer {0}", i), 37 | Id = i, 38 | LastName = string.Format("LastName {0}", i), 39 | JoinedPreferredProgram = i%2 == 0, 40 | NumberFamilyMembersInPlan = i%4, 41 | Region = i%100, 42 | }); 43 | } 44 | } 45 | 46 | public CustomerProvider(DateTime? dateFrom, DateTime? dateTo, string sortField) 47 | : this() 48 | { 49 | if (dateFrom != null) 50 | { 51 | _dateFrom = dateFrom; 52 | } 53 | if (dateTo != null) 54 | { 55 | _dateTo = dateTo; 56 | } 57 | 58 | _sortField = sortField; 59 | } 60 | 61 | public int FetchCount() 62 | { 63 | Thread.Sleep(1000); 64 | _count = _customers.Count(e => e.CustomerSince >= _dateFrom && e.CustomerSince <= _dateTo); 65 | return _count; 66 | } 67 | 68 | public IList FetchRange(int startIndex, int pageCount, out int overallCount) 69 | { 70 | Thread.Sleep(500); 71 | 72 | overallCount = _count; // In this case it's ok not to get the count again because we're assuming the data in the database is not changing. 73 | 74 | if (_sortField.Contains("DESC")) 75 | 76 | return _customers.Where(e => e.CustomerSince >= _dateFrom && e.CustomerSince <= _dateTo) 77 | .OrderBy(e => e.FirstName) 78 | .Skip(startIndex) 79 | .Take(pageCount).ToList(); 80 | else 81 | return _customers.Where(e => e.CustomerSince >= _dateFrom && e.CustomerSince <= _dateTo) 82 | .OrderByDescending(e => e.FirstName) 83 | .Skip(startIndex) 84 | .Take(pageCount).ToList(); 85 | } 86 | } 87 | } -------------------------------------------------------------------------------- /DVFilterSort/Customers.dbml: -------------------------------------------------------------------------------- 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 |
-------------------------------------------------------------------------------- /DVFilterSort/Customers.dbml.layout: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /DVFilterSort/Customers.designer.cs: -------------------------------------------------------------------------------- 1 | #pragma warning disable 1591 2 | //------------------------------------------------------------------------------ 3 | // 4 | // This code was generated by a tool. 5 | // Runtime Version:4.0.21006.1 6 | // 7 | // Changes to this file may cause incorrect behavior and will be lost if 8 | // the code is regenerated. 9 | // 10 | //------------------------------------------------------------------------------ 11 | 12 | namespace DVFilterSort 13 | { 14 | using System.Data.Linq; 15 | using System.Data.Linq.Mapping; 16 | using System.Data; 17 | using System.Collections.Generic; 18 | using System.Reflection; 19 | using System.Linq; 20 | using System.Linq.Expressions; 21 | using System.ComponentModel; 22 | using System; 23 | 24 | 25 | [global::System.Data.Linq.Mapping.DatabaseAttribute(Name="Customers")] 26 | public partial class CustomersDataContext : System.Data.Linq.DataContext 27 | { 28 | 29 | private static System.Data.Linq.Mapping.MappingSource mappingSource = new AttributeMappingSource(); 30 | 31 | #region Extensibility Method Definitions 32 | partial void OnCreated(); 33 | partial void InsertCustomer(Customer instance); 34 | partial void UpdateCustomer(Customer instance); 35 | partial void DeleteCustomer(Customer instance); 36 | #endregion 37 | 38 | public CustomersDataContext() : 39 | base(global::DVFilterSort.Properties.Settings.Default.CustomersConnectionString, mappingSource) 40 | { 41 | OnCreated(); 42 | } 43 | 44 | public CustomersDataContext(string connection) : 45 | base(connection, mappingSource) 46 | { 47 | OnCreated(); 48 | } 49 | 50 | public CustomersDataContext(System.Data.IDbConnection connection) : 51 | base(connection, mappingSource) 52 | { 53 | OnCreated(); 54 | } 55 | 56 | public CustomersDataContext(string connection, System.Data.Linq.Mapping.MappingSource mappingSource) : 57 | base(connection, mappingSource) 58 | { 59 | OnCreated(); 60 | } 61 | 62 | public CustomersDataContext(System.Data.IDbConnection connection, System.Data.Linq.Mapping.MappingSource mappingSource) : 63 | base(connection, mappingSource) 64 | { 65 | OnCreated(); 66 | } 67 | 68 | public System.Data.Linq.Table Customers 69 | { 70 | get 71 | { 72 | return this.GetTable(); 73 | } 74 | } 75 | 76 | [global::System.Data.Linq.Mapping.FunctionAttribute(Name="dbo.GetCount")] 77 | public ISingleResult GetCount([global::System.Data.Linq.Mapping.ParameterAttribute(Name="BeginDate", DbType="DateTime")] System.Nullable beginDate, [global::System.Data.Linq.Mapping.ParameterAttribute(Name="EndDate", DbType="DateTime")] System.Nullable endDate) 78 | { 79 | IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), beginDate, endDate); 80 | return ((ISingleResult)(result.ReturnValue)); 81 | } 82 | 83 | [global::System.Data.Linq.Mapping.FunctionAttribute(Name="dbo.GetSortedFilteredCustomers")] 84 | public ISingleResult GetSortedFilteredCustomers([global::System.Data.Linq.Mapping.ParameterAttribute(Name = "StartIndex", DbType = "Int")] System.Nullable startIndex, [global::System.Data.Linq.Mapping.ParameterAttribute(Name = "EndIndex", DbType = "Int")] System.Nullable endIndex, [global::System.Data.Linq.Mapping.ParameterAttribute(Name = "BeginDate", DbType = "DateTime")] System.Nullable beginDate, [global::System.Data.Linq.Mapping.ParameterAttribute(Name = "EndDate", DbType = "DateTime")] System.Nullable endDate, [global::System.Data.Linq.Mapping.ParameterAttribute(Name = "OrderBy", DbType = "VarChar(500)")] string orderBy) 85 | { 86 | IExecuteResult result = this.ExecuteMethodCall(this, ((MethodInfo)(MethodInfo.GetCurrentMethod())), startIndex, endIndex, beginDate, endDate, orderBy); 87 | return ((ISingleResult)(result.ReturnValue)); 88 | } 89 | } 90 | 91 | [global::System.Data.Linq.Mapping.TableAttribute(Name="dbo.Customer")] 92 | public partial class Customer : INotifyPropertyChanging, INotifyPropertyChanged 93 | { 94 | 95 | private static PropertyChangingEventArgs emptyChangingEventArgs = new PropertyChangingEventArgs(String.Empty); 96 | 97 | private int _Id; 98 | 99 | private string _FirstName; 100 | 101 | private string _LastName; 102 | 103 | private System.DateTime _CustomerSince; 104 | 105 | private double _AmountPaidLocalCalls; 106 | 107 | private double _AmountPaidNationalCalls; 108 | 109 | private double _AmountPaidInternationalCalls; 110 | 111 | private int _NumberFamilyMembersInPlan; 112 | 113 | private bool _JoinedPreferredProgram; 114 | 115 | private int _Region; 116 | 117 | #region Extensibility Method Definitions 118 | partial void OnLoaded(); 119 | partial void OnValidate(System.Data.Linq.ChangeAction action); 120 | partial void OnCreated(); 121 | partial void OnIdChanging(int value); 122 | partial void OnIdChanged(); 123 | partial void OnFirstNameChanging(string value); 124 | partial void OnFirstNameChanged(); 125 | partial void OnLastNameChanging(string value); 126 | partial void OnLastNameChanged(); 127 | partial void OnCustomerSinceChanging(System.DateTime value); 128 | partial void OnCustomerSinceChanged(); 129 | partial void OnAmountPaidLocalCallsChanging(double value); 130 | partial void OnAmountPaidLocalCallsChanged(); 131 | partial void OnAmountPaidNationalCallsChanging(double value); 132 | partial void OnAmountPaidNationalCallsChanged(); 133 | partial void OnAmountPaidInternationalCallsChanging(double value); 134 | partial void OnAmountPaidInternationalCallsChanged(); 135 | partial void OnNumberFamilyMembersInPlanChanging(int value); 136 | partial void OnNumberFamilyMembersInPlanChanged(); 137 | partial void OnJoinedPreferredProgramChanging(bool value); 138 | partial void OnJoinedPreferredProgramChanged(); 139 | partial void OnRegionChanging(int value); 140 | partial void OnRegionChanged(); 141 | #endregion 142 | 143 | public Customer() 144 | { 145 | OnCreated(); 146 | } 147 | 148 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Id", AutoSync=AutoSync.OnInsert, DbType="Int NOT NULL IDENTITY", IsPrimaryKey=true, IsDbGenerated=true)] 149 | public int Id 150 | { 151 | get 152 | { 153 | return this._Id; 154 | } 155 | set 156 | { 157 | if ((this._Id != value)) 158 | { 159 | this.OnIdChanging(value); 160 | this.SendPropertyChanging(); 161 | this._Id = value; 162 | this.SendPropertyChanged("Id"); 163 | this.OnIdChanged(); 164 | } 165 | } 166 | } 167 | 168 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_FirstName", DbType="NVarChar(4000)")] 169 | public string FirstName 170 | { 171 | get 172 | { 173 | return this._FirstName; 174 | } 175 | set 176 | { 177 | if ((this._FirstName != value)) 178 | { 179 | this.OnFirstNameChanging(value); 180 | this.SendPropertyChanging(); 181 | this._FirstName = value; 182 | this.SendPropertyChanged("FirstName"); 183 | this.OnFirstNameChanged(); 184 | } 185 | } 186 | } 187 | 188 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_LastName", DbType="NVarChar(4000)")] 189 | public string LastName 190 | { 191 | get 192 | { 193 | return this._LastName; 194 | } 195 | set 196 | { 197 | if ((this._LastName != value)) 198 | { 199 | this.OnLastNameChanging(value); 200 | this.SendPropertyChanging(); 201 | this._LastName = value; 202 | this.SendPropertyChanged("LastName"); 203 | this.OnLastNameChanged(); 204 | } 205 | } 206 | } 207 | 208 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_CustomerSince", DbType="DateTime NOT NULL")] 209 | public System.DateTime CustomerSince 210 | { 211 | get 212 | { 213 | return this._CustomerSince; 214 | } 215 | set 216 | { 217 | if ((this._CustomerSince != value)) 218 | { 219 | this.OnCustomerSinceChanging(value); 220 | this.SendPropertyChanging(); 221 | this._CustomerSince = value; 222 | this.SendPropertyChanged("CustomerSince"); 223 | this.OnCustomerSinceChanged(); 224 | } 225 | } 226 | } 227 | 228 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_AmountPaidLocalCalls", DbType="Float NOT NULL")] 229 | public double AmountPaidLocalCalls 230 | { 231 | get 232 | { 233 | return this._AmountPaidLocalCalls; 234 | } 235 | set 236 | { 237 | if ((this._AmountPaidLocalCalls != value)) 238 | { 239 | this.OnAmountPaidLocalCallsChanging(value); 240 | this.SendPropertyChanging(); 241 | this._AmountPaidLocalCalls = value; 242 | this.SendPropertyChanged("AmountPaidLocalCalls"); 243 | this.OnAmountPaidLocalCallsChanged(); 244 | } 245 | } 246 | } 247 | 248 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_AmountPaidNationalCalls", DbType="Float NOT NULL")] 249 | public double AmountPaidNationalCalls 250 | { 251 | get 252 | { 253 | return this._AmountPaidNationalCalls; 254 | } 255 | set 256 | { 257 | if ((this._AmountPaidNationalCalls != value)) 258 | { 259 | this.OnAmountPaidNationalCallsChanging(value); 260 | this.SendPropertyChanging(); 261 | this._AmountPaidNationalCalls = value; 262 | this.SendPropertyChanged("AmountPaidNationalCalls"); 263 | this.OnAmountPaidNationalCallsChanged(); 264 | } 265 | } 266 | } 267 | 268 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_AmountPaidInternationalCalls", DbType="Float NOT NULL")] 269 | public double AmountPaidInternationalCalls 270 | { 271 | get 272 | { 273 | return this._AmountPaidInternationalCalls; 274 | } 275 | set 276 | { 277 | if ((this._AmountPaidInternationalCalls != value)) 278 | { 279 | this.OnAmountPaidInternationalCallsChanging(value); 280 | this.SendPropertyChanging(); 281 | this._AmountPaidInternationalCalls = value; 282 | this.SendPropertyChanged("AmountPaidInternationalCalls"); 283 | this.OnAmountPaidInternationalCallsChanged(); 284 | } 285 | } 286 | } 287 | 288 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_NumberFamilyMembersInPlan", DbType="Int NOT NULL")] 289 | public int NumberFamilyMembersInPlan 290 | { 291 | get 292 | { 293 | return this._NumberFamilyMembersInPlan; 294 | } 295 | set 296 | { 297 | if ((this._NumberFamilyMembersInPlan != value)) 298 | { 299 | this.OnNumberFamilyMembersInPlanChanging(value); 300 | this.SendPropertyChanging(); 301 | this._NumberFamilyMembersInPlan = value; 302 | this.SendPropertyChanged("NumberFamilyMembersInPlan"); 303 | this.OnNumberFamilyMembersInPlanChanged(); 304 | } 305 | } 306 | } 307 | 308 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_JoinedPreferredProgram", DbType="Bit NOT NULL")] 309 | public bool JoinedPreferredProgram 310 | { 311 | get 312 | { 313 | return this._JoinedPreferredProgram; 314 | } 315 | set 316 | { 317 | if ((this._JoinedPreferredProgram != value)) 318 | { 319 | this.OnJoinedPreferredProgramChanging(value); 320 | this.SendPropertyChanging(); 321 | this._JoinedPreferredProgram = value; 322 | this.SendPropertyChanged("JoinedPreferredProgram"); 323 | this.OnJoinedPreferredProgramChanged(); 324 | } 325 | } 326 | } 327 | 328 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Region", DbType="Int NOT NULL")] 329 | public int Region 330 | { 331 | get 332 | { 333 | return this._Region; 334 | } 335 | set 336 | { 337 | if ((this._Region != value)) 338 | { 339 | this.OnRegionChanging(value); 340 | this.SendPropertyChanging(); 341 | this._Region = value; 342 | this.SendPropertyChanged("Region"); 343 | this.OnRegionChanged(); 344 | } 345 | } 346 | } 347 | 348 | public event PropertyChangingEventHandler PropertyChanging; 349 | 350 | public event PropertyChangedEventHandler PropertyChanged; 351 | 352 | protected virtual void SendPropertyChanging() 353 | { 354 | if ((this.PropertyChanging != null)) 355 | { 356 | this.PropertyChanging(this, emptyChangingEventArgs); 357 | } 358 | } 359 | 360 | protected virtual void SendPropertyChanged(String propertyName) 361 | { 362 | if ((this.PropertyChanged != null)) 363 | { 364 | this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 365 | } 366 | } 367 | } 368 | 369 | public partial class GetCountResult 370 | { 371 | 372 | private System.Nullable _Count; 373 | 374 | public GetCountResult() 375 | { 376 | } 377 | 378 | [global::System.Data.Linq.Mapping.ColumnAttribute(Storage="_Count", DbType="Int")] 379 | public System.Nullable Count 380 | { 381 | get 382 | { 383 | return this._Count; 384 | } 385 | set 386 | { 387 | if ((this._Count != value)) 388 | { 389 | this._Count = value; 390 | } 391 | } 392 | } 393 | } 394 | } 395 | #pragma warning restore 1591 396 | -------------------------------------------------------------------------------- /DVFilterSort/CustomersDataSet.xsc: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /DVFilterSort/CustomersDataSet.xsd: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | DELETE FROM [dbo].[Customer] WHERE (([Id] = @Original_Id) AND ((@IsNull_FirstName = 1 AND [FirstName] IS NULL) OR ([FirstName] = @Original_FirstName)) AND ((@IsNull_LastName = 1 AND [LastName] IS NULL) OR ([LastName] = @Original_LastName)) AND ([CustomerSince] = @Original_CustomerSince) AND ([AmountPaidLocalCalls] = @Original_AmountPaidLocalCalls) AND ([AmountPaidNationalCalls] = @Original_AmountPaidNationalCalls) AND ([AmountPaidInternationalCalls] = @Original_AmountPaidInternationalCalls) AND ([NumberFamilyMembersInPlan] = @Original_NumberFamilyMembersInPlan) AND ([JoinedPreferredProgram] = @Original_JoinedPreferredProgram) AND ([Region] = @Original_Region)) 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | INSERT INTO [dbo].[Customer] ([FirstName], [LastName], [CustomerSince], [AmountPaidLocalCalls], [AmountPaidNationalCalls], [AmountPaidInternationalCalls], [NumberFamilyMembersInPlan], [JoinedPreferredProgram], [Region]) VALUES (@FirstName, @LastName, @CustomerSince, @AmountPaidLocalCalls, @AmountPaidNationalCalls, @AmountPaidInternationalCalls, @NumberFamilyMembersInPlan, @JoinedPreferredProgram, @Region); 35 | SELECT Id, FirstName, LastName, CustomerSince, AmountPaidLocalCalls, AmountPaidNationalCalls, AmountPaidInternationalCalls, NumberFamilyMembersInPlan, JoinedPreferredProgram, Region FROM Customer WHERE (Id = SCOPE_IDENTITY()) 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | SELECT Id, FirstName, LastName, CustomerSince, AmountPaidLocalCalls, AmountPaidNationalCalls, AmountPaidInternationalCalls, NumberFamilyMembersInPlan, JoinedPreferredProgram, Region FROM dbo.Customer 52 | 53 | 54 | 55 | 56 | 57 | UPDATE [dbo].[Customer] SET [FirstName] = @FirstName, [LastName] = @LastName, [CustomerSince] = @CustomerSince, [AmountPaidLocalCalls] = @AmountPaidLocalCalls, [AmountPaidNationalCalls] = @AmountPaidNationalCalls, [AmountPaidInternationalCalls] = @AmountPaidInternationalCalls, [NumberFamilyMembersInPlan] = @NumberFamilyMembersInPlan, [JoinedPreferredProgram] = @JoinedPreferredProgram, [Region] = @Region WHERE (([Id] = @Original_Id) AND ((@IsNull_FirstName = 1 AND [FirstName] IS NULL) OR ([FirstName] = @Original_FirstName)) AND ((@IsNull_LastName = 1 AND [LastName] IS NULL) OR ([LastName] = @Original_LastName)) AND ([CustomerSince] = @Original_CustomerSince) AND ([AmountPaidLocalCalls] = @Original_AmountPaidLocalCalls) AND ([AmountPaidNationalCalls] = @Original_AmountPaidNationalCalls) AND ([AmountPaidInternationalCalls] = @Original_AmountPaidInternationalCalls) AND ([NumberFamilyMembersInPlan] = @Original_NumberFamilyMembersInPlan) AND ([JoinedPreferredProgram] = @Original_JoinedPreferredProgram) AND ([Region] = @Original_Region)); 58 | SELECT Id, FirstName, LastName, CustomerSince, AmountPaidLocalCalls, AmountPaidNationalCalls, AmountPaidInternationalCalls, NumberFamilyMembersInPlan, JoinedPreferredProgram, Region FROM Customer WHERE (Id = @Id) 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 | dbo.GetCount 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | dbo.GetSortedFilteredCustomers 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 | 184 | 185 | 186 | 187 | -------------------------------------------------------------------------------- /DVFilterSort/CustomersDataSet.xss: -------------------------------------------------------------------------------- 1 |  -------------------------------------------------------------------------------- /DVFilterSort/DVFilterSort.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | x86 6 | 8.0.30703 7 | 2.0 8 | {EB70E3BF-29CE-40C4-A8B6-EBAB16DECD8A} 9 | WinExe 10 | Properties 11 | DVFilterSort 12 | DVFilterSort 13 | v4.0 14 | Client 15 | 512 16 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 17 | 4 18 | 19 | 20 | x86 21 | true 22 | full 23 | false 24 | bin\Debug\ 25 | DEBUG;TRACE 26 | prompt 27 | 4 28 | 29 | 30 | x86 31 | pdbonly 32 | true 33 | bin\Release\ 34 | TRACE 35 | prompt 36 | 4 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 4.0 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | MSBuild:Compile 58 | Designer 59 | 60 | 61 | 62 | 63 | MSBuild:Compile 64 | Designer 65 | 66 | 67 | App.xaml 68 | Code 69 | 70 | 71 | 72 | True 73 | True 74 | Customers.dbml 75 | 76 | 77 | True 78 | True 79 | CustomersDataSet.xsd 80 | 81 | 82 | MainWindow.xaml 83 | Code 84 | 85 | 86 | 87 | 88 | Code 89 | 90 | 91 | True 92 | True 93 | Resources.resx 94 | 95 | 96 | True 97 | Settings.settings 98 | True 99 | 100 | 101 | 102 | Customers.dbml 103 | 104 | 105 | ResXFileCodeGenerator 106 | Resources.Designer.cs 107 | 108 | 109 | MSLinqToSQLGenerator 110 | Customers.designer.cs 111 | Designer 112 | 113 | 114 | CustomersDataSet.xsd 115 | 116 | 117 | MSDataSetGenerator 118 | CustomersDataSet.Designer.cs 119 | Designer 120 | 121 | 122 | CustomersDataSet.xsd 123 | 124 | 125 | SettingsSingleFileGenerator 126 | Settings.Designer.cs 127 | 128 | 129 | 130 | 131 | 132 | {F0551328-4699-43B6-949E-9BDABF89FC1E} 133 | DataVirtualization 134 | 135 | 136 | {37EC527A-D370-4643-A4A5-F585D18244D1} 137 | ReusableControls 138 | 139 | 140 | 141 | 142 | 143 | 144 | 151 | -------------------------------------------------------------------------------- /DVFilterSort/DataGridHelper.cs: -------------------------------------------------------------------------------- 1 | #region 2 | 3 | using System.Windows.Controls; 4 | using System.Windows.Data; 5 | 6 | #endregion 7 | 8 | namespace DVFilterSort 9 | { 10 | public static class DataGridHelper 11 | { 12 | public static string GetSortMemberPath(DataGridColumn column) 13 | { 14 | string sortPropertyName = column.SortMemberPath; 15 | if (string.IsNullOrEmpty(sortPropertyName)) 16 | { 17 | var boundColumn = column as DataGridBoundColumn; 18 | if (boundColumn != null) 19 | { 20 | var binding = boundColumn.Binding as Binding; 21 | if (binding != null) 22 | { 23 | if (!string.IsNullOrEmpty(binding.XPath)) 24 | { 25 | sortPropertyName = binding.XPath; 26 | } 27 | else if (binding.Path != null) 28 | { 29 | sortPropertyName = binding.Path.Path; 30 | } 31 | } 32 | } 33 | } 34 | 35 | return sortPropertyName; 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /DVFilterSort/MainWindow.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 13 | 16 | 17 | 116 | 117 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 195 | 196 | 197 | 198 | 213 | 214 | 217 | 220 | 223 | 226 | 229 | 232 | 235 | 238 | 241 | 242 | 243 | 244 | 245 | -------------------------------------------------------------------------------- /DVFilterSort/MainWindow.xaml.cs: -------------------------------------------------------------------------------- 1 | #region 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.ComponentModel; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.Text; 9 | using System.Windows; 10 | using System.Windows.Controls; 11 | using System.Windows.Input; 12 | using DataVirtualization; 13 | 14 | #endregion 15 | 16 | namespace DVFilterSort 17 | { 18 | /// 19 | /// Interaction logic for MainWindow.xaml 20 | /// 21 | public partial class MainWindow : Window 22 | { 23 | private readonly List sortDescriptions; 24 | private CustomerProvider customerProvider; 25 | private int pageSize = 100; 26 | private int timePageInMemory = 5000; 27 | 28 | public MainWindow() 29 | { 30 | PresentationTraceSources.DataBindingSource.Switch.Level = SourceLevels.Off; 31 | 32 | InitializeComponent(); 33 | 34 | string defaultSortColumnName = "CustomerSince"; 35 | DataGridColumn defaultSortColumn = CustomersDataGrid.Columns.Single(dgc => GetColumnSortMemberPath(dgc) == defaultSortColumnName); 36 | sortDescriptions = new List 37 | { 38 | new CustomSortDescription 39 | { 40 | PropertyName = defaultSortColumnName, 41 | Direction = ListSortDirection.Descending, 42 | Column = defaultSortColumn 43 | } 44 | }; 45 | RefreshData(); 46 | } 47 | 48 | private void CustomerSinceDatePicker_DateChanged(object sender, EventArgs e) 49 | { 50 | RefreshData(); 51 | } 52 | 53 | private void Customers_Sorting(object sender, DataGridSortingEventArgs e) 54 | { 55 | ApplySortColumn(e.Column); 56 | e.Handled = true; 57 | } 58 | 59 | private void RefreshData() 60 | { 61 | string sortString = GetCurrentSortString(); 62 | customerProvider = new CustomerProvider(CustomerSinceDatePicker.DateFrom, CustomerSinceDatePicker.DateTo, sortString); 63 | var customerList = new AsyncVirtualizingCollection(customerProvider, pageSize, timePageInMemory); 64 | DataContext = customerList; 65 | 66 | UpdateSortingVisualFeedback(); 67 | 68 | CustomersDataGrid.SelectedIndex = 0; 69 | } 70 | 71 | private void ApplySortColumn(DataGridColumn column) 72 | { 73 | // If column was not sorted, we sort it ascending. If it was already sorted, we flip the sort direction. 74 | string sortColumn = GetColumnSortMemberPath(column); 75 | CustomSortDescription existingSortDescription = sortDescriptions.SingleOrDefault(sd => sd.PropertyName == sortColumn); 76 | if (existingSortDescription == null) 77 | { 78 | existingSortDescription = new CustomSortDescription 79 | { 80 | PropertyName = sortColumn, 81 | Direction = ListSortDirection.Ascending, 82 | Column = column 83 | }; 84 | sortDescriptions.Add(existingSortDescription); 85 | } 86 | else 87 | { 88 | existingSortDescription.Direction = (existingSortDescription.Direction == ListSortDirection.Ascending) ? ListSortDirection.Descending : ListSortDirection.Ascending; 89 | } 90 | 91 | // If user is not pressing Shift, we remove all SortDescriptions except the current one. 92 | bool isShiftPressed = (Keyboard.Modifiers & ModifierKeys.Shift) != 0; 93 | if (!isShiftPressed) 94 | { 95 | for (int i = sortDescriptions.Count - 1; i >= 0; i--) 96 | { 97 | CustomSortDescription csd = sortDescriptions[i]; 98 | if (csd.PropertyName != sortColumn) 99 | { 100 | sortDescriptions.RemoveAt(i); 101 | } 102 | } 103 | } 104 | 105 | RefreshData(); 106 | } 107 | 108 | private string GetColumnSortMemberPath(DataGridColumn column) 109 | { 110 | string prefixToRemove = "Data."; 111 | string fullSortColumn = DataGridHelper.GetSortMemberPath(column); 112 | string sortColumn = fullSortColumn.Substring(prefixToRemove.Length); 113 | return sortColumn; 114 | } 115 | 116 | private string GetCurrentSortString() 117 | { 118 | // The result string is created, taking into account all sorted columns in the order they were sorted. 119 | var result = new StringBuilder(); 120 | string separator = String.Empty; 121 | foreach (CustomSortDescription sd in sortDescriptions) 122 | { 123 | result.Append(separator); 124 | result.Append(sd.PropertyName); 125 | if (sd.Direction == ListSortDirection.Descending) 126 | { 127 | result = result.Append(" DESC"); 128 | } 129 | separator = ", "; 130 | } 131 | 132 | return result.ToString(); 133 | } 134 | 135 | private void UpdateSortingVisualFeedback() 136 | { 137 | foreach (CustomSortDescription csd in sortDescriptions) 138 | { 139 | csd.Column.SortDirection = csd.Direction; 140 | } 141 | } 142 | } 143 | 144 | public class CustomSortDescription 145 | { 146 | public string PropertyName { get; set; } 147 | public ListSortDirection Direction { get; set; } 148 | public DataGridColumn Column { get; set; } 149 | } 150 | 151 | public enum USRegion 152 | { 153 | Northeast, 154 | Southeast, 155 | Midwest, 156 | Southwest, 157 | West 158 | } 159 | } -------------------------------------------------------------------------------- /DVFilterSort/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("DVFilterSort")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("Microsoft")] 14 | [assembly: AssemblyProduct("DVFilterSort")] 15 | [assembly: AssemblyCopyright("Copyright © Microsoft 2009")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /DVFilterSort/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.21006.1 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DVFilterSort.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DVFilterSort.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /DVFilterSort/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 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 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /DVFilterSort/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.21006.1 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace DVFilterSort.Properties { 12 | 13 | 14 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 15 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] 16 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { 17 | 18 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 19 | 20 | public static Settings Default { 21 | get { 22 | return defaultInstance; 23 | } 24 | } 25 | 26 | [global::System.Configuration.ApplicationScopedSettingAttribute()] 27 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 28 | [global::System.Configuration.SpecialSettingAttribute(global::System.Configuration.SpecialSetting.ConnectionString)] 29 | [global::System.Configuration.DefaultSettingValueAttribute("Data Source=STOLLNITZ-GREEN\\SQLEXPRESS;Initial Catalog=Customers;Integrated Secur" + 30 | "ity=True")] 31 | public string CustomersConnectionString { 32 | get { 33 | return ((string)(this["CustomersConnectionString"])); 34 | } 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /DVFilterSort/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | <?xml version="1.0" encoding="utf-16"?> 7 | <SerializableConnectionString xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"> 8 | <ConnectionString>Data Source=STOLLNITZ-GREEN\SQLEXPRESS;Initial Catalog=Customers;Integrated Security=True</ConnectionString> 9 | <ProviderName>System.Data.SqlClient</ProviderName> 10 | </SerializableConnectionString> 11 | Data Source=STOLLNITZ-GREEN\SQLEXPRESS;Initial Catalog=Customers;Integrated Security=True 12 | 13 | 14 | -------------------------------------------------------------------------------- /DVFilterSort/app.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /DataVirtualization/AsyncVirtualizingCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections.Specialized; 6 | using System.ComponentModel; 7 | using System.Threading; 8 | using System.Collections; 9 | 10 | namespace DataVirtualization 11 | { 12 | /// 13 | /// Derived VirtualizatingCollection, performing loading asychronously. 14 | /// 15 | /// The type of items in the collection 16 | public class AsyncVirtualizingCollection : VirtualizingCollection, INotifyCollectionChanged, INotifyPropertyChanged where T : class 17 | { 18 | /// 19 | /// Initializes a new instance of the class. 20 | /// 21 | /// The items provider. 22 | /// Size of the page. 23 | /// The page timeout. 24 | public AsyncVirtualizingCollection(IItemsProvider itemsProvider, int pageSize, int pageTimeout) 25 | : base(itemsProvider, pageSize, pageTimeout) 26 | { 27 | _synchronizationContext = SynchronizationContext.Current; 28 | } 29 | 30 | #region SynchronizationContext 31 | 32 | private readonly SynchronizationContext _synchronizationContext; 33 | 34 | /// 35 | /// Gets the synchronization context used for UI-related operations. This is obtained as 36 | /// the current SynchronizationContext when the AsyncVirtualizingCollection is created. 37 | /// 38 | /// The synchronization context. 39 | protected SynchronizationContext SynchronizationContext 40 | { 41 | get { return _synchronizationContext; } 42 | } 43 | 44 | #endregion 45 | 46 | #region INotifyCollectionChanged 47 | 48 | /// 49 | /// Occurs when the collection changes. 50 | /// 51 | public event NotifyCollectionChangedEventHandler CollectionChanged; 52 | 53 | /// 54 | /// Raises the event. 55 | /// 56 | /// The instance containing the event data. 57 | protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 58 | { 59 | NotifyCollectionChangedEventHandler h = CollectionChanged; 60 | if (h != null) 61 | h(this, e); 62 | } 63 | 64 | /// 65 | /// Fires the collection reset event. 66 | /// 67 | private void FireCollectionReset() 68 | { 69 | NotifyCollectionChangedEventArgs e = new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); 70 | OnCollectionChanged(e); 71 | } 72 | 73 | #endregion 74 | 75 | #region INotifyPropertyChanged 76 | 77 | /// 78 | /// Occurs when a property value changes. 79 | /// 80 | public event PropertyChangedEventHandler PropertyChanged; 81 | 82 | /// 83 | /// Raises the event. 84 | /// 85 | /// The instance containing the event data. 86 | protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 87 | { 88 | PropertyChangedEventHandler h = PropertyChanged; 89 | if (h != null) 90 | h(this, e); 91 | } 92 | 93 | /// 94 | /// Fires the property changed event. 95 | /// 96 | /// Name of the property. 97 | private void FirePropertyChanged(string propertyName) 98 | { 99 | PropertyChangedEventArgs e = new PropertyChangedEventArgs(propertyName); 100 | OnPropertyChanged(e); 101 | } 102 | 103 | #endregion 104 | 105 | #region IsLoading 106 | 107 | private bool _isLoading; 108 | 109 | /// 110 | /// Gets or sets a value indicating whether the collection is loading. 111 | /// 112 | /// 113 | /// true if this collection is loading; otherwise, false. 114 | /// 115 | public bool IsLoading 116 | { 117 | get 118 | { 119 | return _isLoading; 120 | } 121 | set 122 | { 123 | if (value != _isLoading) 124 | { 125 | _isLoading = value; 126 | FirePropertyChanged("IsLoading"); 127 | } 128 | } 129 | } 130 | 131 | private bool _isInitializing; 132 | 133 | public bool IsInitializing 134 | { 135 | get 136 | { 137 | return _isInitializing; 138 | } 139 | set 140 | { 141 | if (value != _isInitializing) 142 | { 143 | _isInitializing = value; 144 | FirePropertyChanged("IsInitializing"); 145 | } 146 | } 147 | } 148 | #endregion 149 | 150 | #region Load overrides 151 | 152 | /// 153 | /// Asynchronously loads the count of items. 154 | /// 155 | protected override void LoadCount() 156 | { 157 | if (Count == 0) 158 | { 159 | IsInitializing = true; 160 | } 161 | ThreadPool.QueueUserWorkItem(LoadCountWork); 162 | } 163 | 164 | /// 165 | /// Performed on background thread. 166 | /// 167 | /// None required. 168 | private void LoadCountWork(object args) 169 | { 170 | int count = FetchCount(); 171 | SynchronizationContext.Send(LoadCountCompleted, count); 172 | } 173 | 174 | /// 175 | /// Performed on UI-thread after LoadCountWork. 176 | /// 177 | /// Number of items returned. 178 | protected virtual void LoadCountCompleted(object args) 179 | { 180 | int newCount = (int)args; 181 | this.TakeNewCount(newCount); 182 | IsInitializing = false; 183 | } 184 | 185 | private void TakeNewCount(int newCount) 186 | { 187 | if (newCount != this.Count) 188 | { 189 | this.Count = newCount; 190 | this.EmptyCache(); 191 | FireCollectionReset(); 192 | } 193 | } 194 | 195 | /// 196 | /// Asynchronously loads the page. 197 | /// 198 | /// The index. 199 | protected override void LoadPage(int pageIndex, int pageLength) 200 | { 201 | IsLoading = true; 202 | ThreadPool.QueueUserWorkItem(LoadPageWork, new int[] { pageIndex, pageLength }); 203 | } 204 | 205 | /// 206 | /// Performed on background thread. 207 | /// 208 | /// Index of the page to load. 209 | private void LoadPageWork(object state) 210 | { 211 | int[] args = (int[])state; 212 | int pageIndex = args[0]; 213 | int pageLength = args[1]; 214 | int overallCount = 0; 215 | IList dataItems = FetchPage(pageIndex, pageLength, out overallCount); 216 | SynchronizationContext.Send(LoadPageCompleted, new object[] { pageIndex, dataItems, overallCount }); 217 | } 218 | 219 | /// 220 | /// Performed on UI-thread after LoadPageWork. 221 | /// 222 | /// object[] { int pageIndex, IList(T) page } 223 | private void LoadPageCompleted(object state) 224 | { 225 | object[] args = (object[])state; 226 | int pageIndex = (int)args[0]; 227 | IList dataItems = (IList)args[1]; 228 | int newCount = (int)args[2]; 229 | this.TakeNewCount(newCount); 230 | 231 | PopulatePage(pageIndex, dataItems); 232 | IsLoading = false; 233 | } 234 | 235 | #endregion 236 | } 237 | } 238 | -------------------------------------------------------------------------------- /DataVirtualization/DataPage.cs: -------------------------------------------------------------------------------- 1 | #region 2 | 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | 7 | #endregion 8 | 9 | namespace DataVirtualization 10 | { 11 | public class DataPage where T : class 12 | { 13 | public DataPage(int firstIndex, int pageLength) 14 | { 15 | Items = new List>(pageLength); 16 | for (int i = 0; i < pageLength; i++) 17 | { 18 | Items.Add(new DataWrapper(firstIndex + i)); 19 | } 20 | TouchTime = DateTime.Now; 21 | } 22 | 23 | public IList> Items { get; private set; } 24 | 25 | public DateTime TouchTime { get; set; } 26 | 27 | public bool IsInUse 28 | { 29 | get { return Items.Any(wrapper => wrapper.IsInUse); } 30 | } 31 | 32 | public void Populate(IList newItems) 33 | { 34 | int i; 35 | int index = 0; 36 | for (i = 0; i < newItems.Count && i < Items.Count; i++) 37 | { 38 | Items[i].Data = newItems[i]; 39 | index = Items[i].Index; 40 | } 41 | 42 | while (i < newItems.Count) 43 | { 44 | index++; 45 | Items.Add(new DataWrapper(index) {Data = newItems[i]}); 46 | i++; 47 | } 48 | 49 | while (i < Items.Count) 50 | { 51 | Items.RemoveAt(Items.Count - 1); 52 | } 53 | } 54 | } 55 | } -------------------------------------------------------------------------------- /DataVirtualization/DataVirtualization.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {F0551328-4699-43B6-949E-9BDABF89FC1E} 9 | Library 10 | Properties 11 | DataVirtualization 12 | DataVirtualization 13 | v4.0 14 | 512 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | 25 | 26 | pdbonly 27 | true 28 | bin\Release\ 29 | TRACE 30 | prompt 31 | 4 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 58 | -------------------------------------------------------------------------------- /DataVirtualization/DataWrapper.cs: -------------------------------------------------------------------------------- 1 | using System.ComponentModel; 2 | 3 | namespace DataVirtualization 4 | { 5 | public class DataWrapper : INotifyPropertyChanged where T : class 6 | { 7 | private int index; 8 | private T data; 9 | 10 | public event PropertyChangedEventHandler PropertyChanged; 11 | 12 | public DataWrapper(int index) 13 | { 14 | this.index = index; 15 | } 16 | 17 | public int Index 18 | { 19 | get { return this.index; } 20 | } 21 | 22 | public int ItemNumber 23 | { 24 | get { return this.index + 1; } 25 | } 26 | 27 | public bool IsLoading 28 | { 29 | get { return this.Data == null; } 30 | } 31 | 32 | public T Data 33 | { 34 | get { return this.data; } 35 | internal set 36 | { 37 | this.data = value; 38 | this.OnPropertyChanged("Data"); 39 | this.OnPropertyChanged("IsLoading"); 40 | } 41 | } 42 | 43 | public bool IsInUse 44 | { 45 | get { return this.PropertyChanged != null; } 46 | } 47 | 48 | private void OnPropertyChanged(string propertyName) 49 | { 50 | System.Diagnostics.Debug.Assert(this.GetType().GetProperty(propertyName) != null); 51 | var handler = this.PropertyChanged; 52 | if (handler != null) 53 | { 54 | handler(this, new PropertyChangedEventArgs(propertyName)); 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /DataVirtualization/IItemsProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | 6 | namespace DataVirtualization 7 | { 8 | /// 9 | /// Represents a provider of collection details. 10 | /// 11 | /// The type of items in the collection. 12 | public interface IItemsProvider 13 | { 14 | /// 15 | /// Fetches the total number of items available. 16 | /// 17 | /// 18 | int FetchCount(); 19 | 20 | /// 21 | /// Fetches a range of items. 22 | /// 23 | /// The start index. 24 | /// The number of items to fetch. 25 | /// 26 | IList FetchRange(int startIndex, int pageCount, out int overallCount); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /DataVirtualization/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("DataVirtualization")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("DataVirtualization")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2009")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("5c878b02-f171-4afd-aa12-94cbdac79742")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /DataVirtualization/VirtualizingCollection.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Collections; 6 | using System.Diagnostics; 7 | using System.ComponentModel; 8 | 9 | namespace DataVirtualization 10 | { 11 | /// 12 | /// Specialized list implementation that provides data virtualization. The collection is divided up into pages, 13 | /// and pages are dynamically fetched from the IItemsProvider when required. Stale pages are removed after a 14 | /// configurable period of time. 15 | /// Intended for use with large collections on a network or disk resource that cannot be instantiated locally 16 | /// due to memory consumption or fetch latency. 17 | /// 18 | /// 19 | /// The IList implmentation is not fully complete, but should be sufficient for use as read only collection 20 | /// data bound to a suitable ItemsControl. 21 | /// 22 | /// 23 | public class VirtualizingCollection : IList>, IList where T : class 24 | { 25 | #region Constructors 26 | 27 | /// 28 | /// Initializes a new instance of the class. 29 | /// 30 | /// The items provider. 31 | /// Size of the page. 32 | /// The page timeout. 33 | public VirtualizingCollection(IItemsProvider itemsProvider, int pageSize, int pageTimeout) 34 | { 35 | _itemsProvider = itemsProvider; 36 | _pageSize = pageSize; 37 | _pageTimeout = pageTimeout; 38 | } 39 | 40 | /// 41 | /// Initializes a new instance of the class. 42 | /// 43 | /// The items provider. 44 | /// Size of the page. 45 | public VirtualizingCollection(IItemsProvider itemsProvider, int pageSize) 46 | { 47 | _itemsProvider = itemsProvider; 48 | _pageSize = pageSize; 49 | } 50 | 51 | /// 52 | /// Initializes a new instance of the class. 53 | /// 54 | /// The items provider. 55 | public VirtualizingCollection(IItemsProvider itemsProvider) 56 | { 57 | _itemsProvider = itemsProvider; 58 | } 59 | 60 | #endregion 61 | 62 | #region ItemsProvider 63 | 64 | private readonly IItemsProvider _itemsProvider; 65 | 66 | /// 67 | /// Gets the items provider. 68 | /// 69 | /// The items provider. 70 | public IItemsProvider ItemsProvider 71 | { 72 | get { return _itemsProvider; } 73 | } 74 | 75 | #endregion 76 | 77 | #region PageSize 78 | 79 | private readonly int _pageSize = 100; 80 | 81 | /// 82 | /// Gets the size of the page. 83 | /// 84 | /// The size of the page. 85 | public int PageSize 86 | { 87 | get { return _pageSize; } 88 | } 89 | 90 | #endregion 91 | 92 | #region PageTimeout 93 | 94 | private readonly long _pageTimeout = 10000; 95 | 96 | /// 97 | /// Gets the page timeout. 98 | /// 99 | /// The page timeout. 100 | public long PageTimeout 101 | { 102 | get { return _pageTimeout; } 103 | } 104 | 105 | #endregion 106 | 107 | #region IList>, IList 108 | 109 | #region Count 110 | 111 | private int _count = -1; 112 | 113 | /// 114 | /// Gets the number of elements contained in the . 115 | /// The first time this property is accessed, it will fetch the count from the IItemsProvider. 116 | /// 117 | /// 118 | /// 119 | /// The number of elements contained in the . 120 | /// 121 | public int Count 122 | { 123 | get 124 | { 125 | if (_count == -1) 126 | { 127 | _count = 0; 128 | LoadCount(); 129 | } 130 | return _count; 131 | } 132 | protected set 133 | { 134 | _count = value; 135 | } 136 | } 137 | 138 | #endregion 139 | 140 | #region Indexer 141 | 142 | /// 143 | /// Gets the item at the specified index. This property will fetch 144 | /// the corresponding page from the IItemsProvider if required. 145 | /// 146 | /// 147 | public DataWrapper this[int index] 148 | { 149 | get 150 | { 151 | // determine which page and offset within page 152 | int pageIndex = index / PageSize; 153 | int pageOffset = index % PageSize; 154 | 155 | // request primary page 156 | RequestPage(pageIndex); 157 | 158 | // if accessing upper 50% then request next page 159 | if (pageOffset > PageSize / 2 && pageIndex < Count / PageSize) 160 | RequestPage(pageIndex + 1); 161 | 162 | // if accessing lower 50% then request prev page 163 | if (pageOffset < PageSize / 2 && pageIndex > 0) 164 | RequestPage(pageIndex - 1); 165 | 166 | // remove stale pages 167 | CleanUpPages(); 168 | 169 | // return requested item 170 | return _pages[pageIndex].Items[pageOffset]; 171 | } 172 | set { throw new NotSupportedException(); } 173 | } 174 | 175 | object IList.this[int index] 176 | { 177 | get { return this[index]; } 178 | set { throw new NotSupportedException(); } 179 | } 180 | 181 | #endregion 182 | 183 | #region IEnumerator>, IEnumerator 184 | 185 | /// 186 | /// Returns an enumerator that iterates through the collection. 187 | /// 188 | /// 189 | /// This method should be avoided on large collections due to poor performance. 190 | /// 191 | /// 192 | /// A that can be used to iterate through the collection. 193 | /// 194 | public IEnumerator> GetEnumerator() 195 | { 196 | for (int i = 0; i < Count; i++) 197 | { 198 | yield return this[i]; 199 | } 200 | } 201 | 202 | /// 203 | /// Returns an enumerator that iterates through a collection. 204 | /// 205 | /// 206 | /// An object that can be used to iterate through the collection. 207 | /// 208 | IEnumerator IEnumerable.GetEnumerator() 209 | { 210 | return GetEnumerator(); 211 | } 212 | 213 | #endregion 214 | 215 | #region Add 216 | 217 | /// 218 | /// Not supported. 219 | /// 220 | /// The object to add to the . 221 | /// 222 | /// The is read-only. 223 | /// 224 | public void Add(DataWrapper item) 225 | { 226 | throw new NotSupportedException(); 227 | } 228 | 229 | int IList.Add(object value) 230 | { 231 | throw new NotSupportedException(); 232 | } 233 | 234 | #endregion 235 | 236 | #region Contains 237 | 238 | bool IList.Contains(object value) 239 | { 240 | return Contains((DataWrapper)value); 241 | } 242 | 243 | /// 244 | /// Not supported. 245 | /// 246 | /// The object to locate in the . 247 | /// 248 | /// Always false. 249 | /// 250 | public bool Contains(DataWrapper item) 251 | { 252 | foreach (DataPage page in _pages.Values) 253 | { 254 | if (page.Items.Contains(item)) 255 | { 256 | return true; 257 | } 258 | } 259 | return false; 260 | } 261 | 262 | #endregion 263 | 264 | #region Clear 265 | 266 | /// 267 | /// TODO 268 | /// 269 | public void Clear() 270 | { 271 | throw new NotSupportedException(); 272 | } 273 | 274 | #endregion 275 | 276 | #region IndexOf 277 | 278 | int IList.IndexOf(object value) 279 | { 280 | return IndexOf((DataWrapper)value); 281 | } 282 | 283 | /// 284 | /// TODO 285 | /// 286 | /// The object to locate in the . 287 | /// 288 | /// TODO 289 | /// 290 | public int IndexOf(DataWrapper item) 291 | { 292 | foreach (KeyValuePair> keyValuePair in _pages) 293 | { 294 | int indexWithinPage = keyValuePair.Value.Items.IndexOf(item); 295 | if (indexWithinPage != -1) 296 | { 297 | return PageSize * keyValuePair.Key + indexWithinPage; 298 | } 299 | } 300 | return -1; 301 | } 302 | 303 | #endregion 304 | 305 | #region Insert 306 | 307 | /// 308 | /// Not supported. 309 | /// 310 | /// The zero-based index at which should be inserted. 311 | /// The object to insert into the . 312 | /// 313 | /// is not a valid index in the . 314 | /// 315 | /// 316 | /// The is read-only. 317 | /// 318 | public void Insert(int index, DataWrapper item) 319 | { 320 | throw new NotSupportedException(); 321 | } 322 | 323 | void IList.Insert(int index, object value) 324 | { 325 | Insert(index, (DataWrapper)value); 326 | } 327 | 328 | #endregion 329 | 330 | #region Remove 331 | 332 | /// 333 | /// Not supported. 334 | /// 335 | /// The zero-based index of the item to remove. 336 | /// 337 | /// is not a valid index in the . 338 | /// 339 | /// 340 | /// The is read-only. 341 | /// 342 | public void RemoveAt(int index) 343 | { 344 | throw new NotSupportedException(); 345 | } 346 | 347 | void IList.Remove(object value) 348 | { 349 | throw new NotSupportedException(); 350 | } 351 | 352 | /// 353 | /// Not supported. 354 | /// 355 | /// The object to remove from the . 356 | /// 357 | /// true if was successfully removed from the ; otherwise, false. This method also returns false if is not found in the original . 358 | /// 359 | /// 360 | /// The is read-only. 361 | /// 362 | public bool Remove(DataWrapper item) 363 | { 364 | throw new NotSupportedException(); 365 | } 366 | 367 | #endregion 368 | 369 | #region CopyTo 370 | 371 | /// 372 | /// Not supported. 373 | /// 374 | /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. 375 | /// The zero-based index in at which copying begins. 376 | /// 377 | /// is null. 378 | /// 379 | /// 380 | /// is less than 0. 381 | /// 382 | /// 383 | /// is multidimensional. 384 | /// -or- 385 | /// is equal to or greater than the length of . 386 | /// -or- 387 | /// The number of elements in the source is greater than the available space from to the end of the destination . 388 | /// -or- 389 | /// Type cannot be cast automatically to the type of the destination . 390 | /// 391 | public void CopyTo(DataWrapper[] array, int arrayIndex) 392 | { 393 | throw new NotSupportedException(); 394 | } 395 | 396 | void ICollection.CopyTo(Array array, int index) 397 | { 398 | throw new NotSupportedException(); 399 | } 400 | 401 | #endregion 402 | 403 | #region Misc 404 | 405 | /// 406 | /// Gets an object that can be used to synchronize access to the . 407 | /// 408 | /// 409 | /// 410 | /// An object that can be used to synchronize access to the . 411 | /// 412 | public object SyncRoot 413 | { 414 | get { return this; } 415 | } 416 | 417 | /// 418 | /// Gets a value indicating whether access to the is synchronized (thread safe). 419 | /// 420 | /// 421 | /// Always false. 422 | /// 423 | public bool IsSynchronized 424 | { 425 | get { return false; } 426 | } 427 | 428 | /// 429 | /// Gets a value indicating whether the is read-only. 430 | /// 431 | /// 432 | /// Always true. 433 | /// 434 | public bool IsReadOnly 435 | { 436 | get { return true; } 437 | } 438 | 439 | /// 440 | /// Gets a value indicating whether the has a fixed size. 441 | /// 442 | /// 443 | /// Always false. 444 | /// 445 | public bool IsFixedSize 446 | { 447 | get { return false; } 448 | } 449 | 450 | #endregion 451 | 452 | #endregion 453 | 454 | #region Paging 455 | 456 | private Dictionary> _pages = new Dictionary>(); 457 | 458 | /// 459 | /// Cleans up any stale pages that have not been accessed in the period dictated by PageTimeout. 460 | /// 461 | public void CleanUpPages() 462 | { 463 | int[] keys = _pages.Keys.ToArray(); 464 | foreach (int key in keys) 465 | { 466 | // page 0 is a special case, since WPF ItemsControl access the first item frequently 467 | if (key != 0 && (DateTime.Now - _pages[key].TouchTime).TotalMilliseconds > PageTimeout) 468 | { 469 | bool removePage = true; 470 | DataPage page; 471 | if (_pages.TryGetValue(key, out page)) 472 | { 473 | removePage = !page.IsInUse; 474 | } 475 | 476 | if (removePage) 477 | { 478 | _pages.Remove(key); 479 | Trace.WriteLine("Removed Page: " + key); 480 | } 481 | } 482 | } 483 | } 484 | 485 | /// 486 | /// Makes a request for the specified page, creating the necessary slots in the dictionary, 487 | /// and updating the page touch time. 488 | /// 489 | /// Index of the page. 490 | protected virtual void RequestPage(int pageIndex) 491 | { 492 | if (!_pages.ContainsKey(pageIndex)) 493 | { 494 | // Create a page of empty data wrappers. 495 | int pageLength = Math.Min(this.PageSize, this.Count - pageIndex * this.PageSize); 496 | DataPage page = new DataPage(pageIndex * this.PageSize, pageLength); 497 | _pages.Add(pageIndex, page); 498 | Trace.WriteLine("Added page: " + pageIndex); 499 | LoadPage(pageIndex, pageLength); 500 | } 501 | else 502 | { 503 | _pages[pageIndex].TouchTime = DateTime.Now; 504 | } 505 | } 506 | 507 | /// 508 | /// Populates the page within the dictionary. 509 | /// 510 | /// Index of the page. 511 | /// The page. 512 | protected virtual void PopulatePage(int pageIndex, IList dataItems) 513 | { 514 | Trace.WriteLine("Page populated: " + pageIndex); 515 | DataPage page; 516 | if (_pages.TryGetValue(pageIndex, out page)) 517 | { 518 | page.Populate(dataItems); 519 | } 520 | } 521 | 522 | /// 523 | /// Removes all cached pages. This is useful when the count of the 524 | /// underlying collection changes. 525 | /// 526 | protected void EmptyCache() 527 | { 528 | _pages = new Dictionary>(); 529 | } 530 | 531 | #endregion 532 | 533 | #region Load methods 534 | 535 | /// 536 | /// Loads the count of items. 537 | /// 538 | protected virtual void LoadCount() 539 | { 540 | this.Count = FetchCount(); 541 | } 542 | 543 | /// 544 | /// Loads the page of items. 545 | /// 546 | /// Index of the page. 547 | /// Number of items in the page. 548 | protected virtual void LoadPage(int pageIndex, int pageLength) 549 | { 550 | int count = 0; 551 | PopulatePage(pageIndex, FetchPage(pageIndex, pageLength, out count)); 552 | this.Count = count; 553 | } 554 | 555 | #endregion 556 | 557 | #region Fetch methods 558 | 559 | /// 560 | /// Fetches the requested page from the IItemsProvider. 561 | /// 562 | /// Index of the page. 563 | /// 564 | protected IList FetchPage(int pageIndex, int pageLength, out int count) 565 | { 566 | return ItemsProvider.FetchRange(pageIndex * PageSize, pageLength, out count); 567 | } 568 | 569 | /// 570 | /// Fetches the count of itmes from the IItemsProvider. 571 | /// 572 | /// 573 | protected int FetchCount() 574 | { 575 | return ItemsProvider.FetchCount(); 576 | } 577 | 578 | #endregion 579 | } 580 | } 581 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Virtualization 2 | ============== 3 | 4 | Data virtualization in WPF, UI virtualization 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation 7 | files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, 8 | modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the 9 | Software is furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the 12 | Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE 15 | WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 16 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 17 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | -------------------------------------------------------------------------------- /ReusableControls/DateRangePicker.xaml: -------------------------------------------------------------------------------- 1 |  8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /ReusableControls/DateRangePicker.xaml.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Windows; 6 | using System.Windows.Controls; 7 | using System.Windows.Data; 8 | using System.Windows.Documents; 9 | using System.Windows.Input; 10 | using System.Windows.Media; 11 | using System.Windows.Media.Imaging; 12 | using System.Windows.Navigation; 13 | using System.Windows.Shapes; 14 | 15 | namespace ReusableControls 16 | { 17 | public partial class DateRangePicker : UserControl 18 | { 19 | public event EventHandler FromDateChanged; 20 | public event EventHandler ToDateChanged; 21 | 22 | public Nullable DateFrom 23 | { 24 | get { return (Nullable)this.GetValue(DateFromProperty); } 25 | set { this.SetValue(DateFromProperty, value); } 26 | } 27 | 28 | public static readonly DependencyProperty DateFromProperty = 29 | DependencyProperty.Register("DateFrom", typeof(Nullable), typeof(DateRangePicker), new PropertyMetadata(DateFrom_PropertyChanged)); 30 | 31 | 32 | public Nullable DateTo 33 | { 34 | get { return (Nullable)this.GetValue(DateToProperty); } 35 | set { this.SetValue(DateToProperty, value); } 36 | } 37 | 38 | public static readonly DependencyProperty DateToProperty = 39 | DependencyProperty.Register("DateTo", typeof(Nullable), typeof(DateRangePicker), new PropertyMetadata(DateTo_PropertyChanged)); 40 | 41 | public DateRangePicker() 42 | { 43 | this.InitializeComponent(); 44 | 45 | this.DatePickerFrom.BlackoutDates.Add(new CalendarDateRange(DateTime.Today.AddDays(1), DateTime.MaxValue)); 46 | this.DatePickerTo.BlackoutDates.Add(new CalendarDateRange(DateTime.Today.AddDays(1), DateTime.MaxValue)); 47 | 48 | this.DatePickerFrom.SetBinding(DatePicker.SelectedDateProperty, new Binding("DateFrom") { Source = this, Mode = BindingMode.TwoWay }); 49 | this.DatePickerTo.SetBinding(DatePicker.SelectedDateProperty, new Binding("DateTo") { Source = this, Mode = BindingMode.TwoWay }); 50 | } 51 | 52 | private static void DateFrom_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 53 | { 54 | DateRangePicker dateRangePicker = (DateRangePicker)obj; 55 | dateRangePicker.DateFromChanged(); 56 | } 57 | 58 | private void DateFromChanged() 59 | { 60 | // This updates the blackout dates for DatePickerTo. 61 | this.DatePickerTo.BlackoutDates.Clear(); 62 | if (this.DateFrom.HasValue) 63 | { 64 | DateTime dateFrom = this.DateFrom.Value; 65 | if (this.DateTo.HasValue) 66 | { 67 | DateTime dateTo = this.DateTo.Value; 68 | if (dateTo <= dateFrom) 69 | { 70 | this.DateTo = null; 71 | } 72 | } 73 | 74 | this.DatePickerTo.BlackoutDates.Add(new CalendarDateRange(DateTime.MinValue, dateFrom)); 75 | } 76 | this.DatePickerTo.BlackoutDates.Add(new CalendarDateRange(DateTime.Today.AddDays(1), DateTime.MaxValue)); 77 | 78 | this.OnDateChanged(FromDateChanged); 79 | } 80 | 81 | private static void DateTo_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 82 | { 83 | DateRangePicker dateRangePicker = (DateRangePicker)obj; 84 | dateRangePicker.OnDateChanged(dateRangePicker.ToDateChanged); 85 | } 86 | 87 | private void OnDateChanged(EventHandler handler) 88 | { 89 | if (handler != null) 90 | { 91 | handler(this, EventArgs.Empty); 92 | } 93 | } 94 | } 95 | } 96 | -------------------------------------------------------------------------------- /ReusableControls/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Resources; 3 | using System.Runtime.CompilerServices; 4 | using System.Runtime.InteropServices; 5 | using System.Windows; 6 | 7 | // General Information about an assembly is controlled through the following 8 | // set of attributes. Change these attribute values to modify the information 9 | // associated with an assembly. 10 | [assembly: AssemblyTitle("ReusableControls")] 11 | [assembly: AssemblyDescription("")] 12 | [assembly: AssemblyConfiguration("")] 13 | [assembly: AssemblyCompany("Microsoft")] 14 | [assembly: AssemblyProduct("ReusableControls")] 15 | [assembly: AssemblyCopyright("Copyright © Microsoft 2009")] 16 | [assembly: AssemblyTrademark("")] 17 | [assembly: AssemblyCulture("")] 18 | 19 | // Setting ComVisible to false makes the types in this assembly not visible 20 | // to COM components. If you need to access a type in this assembly from 21 | // COM, set the ComVisible attribute to true on that type. 22 | [assembly: ComVisible(false)] 23 | 24 | //In order to begin building localizable applications, set 25 | //CultureYouAreCodingWith in your .csproj file 26 | //inside a . For example, if you are using US english 27 | //in your source files, set the to en-US. Then uncomment 28 | //the NeutralResourceLanguage attribute below. Update the "en-US" in 29 | //the line below to match the UICulture setting in the project file. 30 | 31 | //[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] 32 | 33 | 34 | [assembly: ThemeInfo( 35 | ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located 36 | //(used if a resource is not found in the page, 37 | // or application resource dictionaries) 38 | ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located 39 | //(used if a resource is not found in the page, 40 | // app, or any theme specific resource dictionaries) 41 | )] 42 | 43 | 44 | // Version information for an assembly consists of the following four values: 45 | // 46 | // Major Version 47 | // Minor Version 48 | // Build Number 49 | // Revision 50 | // 51 | // You can specify all the values or you can default the Build and Revision Numbers 52 | // by using the '*' as shown below: 53 | // [assembly: AssemblyVersion("1.0.*")] 54 | [assembly: AssemblyVersion("1.0.0.0")] 55 | [assembly: AssemblyFileVersion("1.0.0.0")] 56 | -------------------------------------------------------------------------------- /ReusableControls/Properties/Resources.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.21006.1 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ReusableControls.Properties 12 | { 13 | 14 | 15 | /// 16 | /// A strongly-typed resource class, for looking up localized strings, etc. 17 | /// 18 | // This class was auto-generated by the StronglyTypedResourceBuilder 19 | // class via a tool like ResGen or Visual Studio. 20 | // To add or remove a member, edit your .ResX file then rerun ResGen 21 | // with the /str option, or rebuild your VS project. 22 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] 23 | [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] 24 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 25 | internal class Resources 26 | { 27 | 28 | private static global::System.Resources.ResourceManager resourceMan; 29 | 30 | private static global::System.Globalization.CultureInfo resourceCulture; 31 | 32 | [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] 33 | internal Resources() 34 | { 35 | } 36 | 37 | /// 38 | /// Returns the cached ResourceManager instance used by this class. 39 | /// 40 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 41 | internal static global::System.Resources.ResourceManager ResourceManager 42 | { 43 | get 44 | { 45 | if ((resourceMan == null)) 46 | { 47 | global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("ReusableControls.Properties.Resources", typeof(Resources).Assembly); 48 | resourceMan = temp; 49 | } 50 | return resourceMan; 51 | } 52 | } 53 | 54 | /// 55 | /// Overrides the current thread's CurrentUICulture property for all 56 | /// resource lookups using this strongly typed resource class. 57 | /// 58 | [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] 59 | internal static global::System.Globalization.CultureInfo Culture 60 | { 61 | get 62 | { 63 | return resourceCulture; 64 | } 65 | set 66 | { 67 | resourceCulture = value; 68 | } 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /ReusableControls/Properties/Resources.resx: -------------------------------------------------------------------------------- 1 |  2 | 3 | 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 | text/microsoft-resx 107 | 108 | 109 | 2.0 110 | 111 | 112 | System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 113 | 114 | 115 | System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 116 | 117 | -------------------------------------------------------------------------------- /ReusableControls/Properties/Settings.Designer.cs: -------------------------------------------------------------------------------- 1 | //------------------------------------------------------------------------------ 2 | // 3 | // This code was generated by a tool. 4 | // Runtime Version:4.0.21006.1 5 | // 6 | // Changes to this file may cause incorrect behavior and will be lost if 7 | // the code is regenerated. 8 | // 9 | //------------------------------------------------------------------------------ 10 | 11 | namespace ReusableControls.Properties 12 | { 13 | 14 | 15 | [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] 16 | [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "10.0.0.0")] 17 | internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase 18 | { 19 | 20 | private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); 21 | 22 | public static Settings Default 23 | { 24 | get 25 | { 26 | return defaultInstance; 27 | } 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /ReusableControls/Properties/Settings.settings: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /ReusableControls/ReusableControls.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | Debug 5 | AnyCPU 6 | 8.0.30703 7 | 2.0 8 | {37EC527A-D370-4643-A4A5-F585D18244D1} 9 | library 10 | Properties 11 | ReusableControls 12 | ReusableControls 13 | v4.0 14 | Client 15 | 512 16 | {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 17 | 4 18 | 19 | 20 | true 21 | full 22 | false 23 | bin\Debug\ 24 | DEBUG;TRACE 25 | prompt 26 | 4 27 | 28 | 29 | pdbonly 30 | true 31 | bin\Release\ 32 | TRACE 33 | prompt 34 | 4 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 4.0 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | MSBuild:Compile 54 | Designer 55 | 56 | 57 | DateRangePicker.xaml 58 | Code 59 | 60 | 61 | 62 | 63 | Code 64 | 65 | 66 | True 67 | True 68 | Resources.resx 69 | 70 | 71 | True 72 | Settings.settings 73 | True 74 | 75 | 76 | ResXFileCodeGenerator 77 | Resources.Designer.cs 78 | 79 | 80 | SettingsSingleFileGenerator 81 | Settings.Designer.cs 82 | 83 | 84 | 85 | 86 | 93 | --------------------------------------------------------------------------------