From 91b317d379699b147421dc072f5acbd6c08e7387 Mon Sep 17 00:00:00 2001 From: Jan Pluskal Date: Sun, 17 Dec 2017 15:27:52 +0100 Subject: [PATCH 01/20] Add DataGridAsyncDemoMVVM simple, withou filtering and sorting --- AlphaChiTech.Virtualization.sln | 13 +- DataGridAsyncDemoMVVM/App.config | 7 + DataGridAsyncDemoMVVM/App.xaml | 11 + DataGridAsyncDemoMVVM/App.xaml.cs | 17 ++ .../DataGridAsyncDemoMVVM.csproj | 119 ++++++++ DataGridAsyncDemoMVVM/MainViewModel.cs | 30 ++ DataGridAsyncDemoMVVM/MainWindow.xaml | 50 ++++ DataGridAsyncDemoMVVM/MainWindow.xaml.cs | 42 +++ .../Properties/AssemblyInfo.cs | 53 ++++ .../Properties/Resources.Designer.cs | 71 +++++ .../Properties/Resources.resx | 117 ++++++++ .../Properties/Settings.Designer.cs | 30 ++ .../Properties/Settings.settings | 8 + DataGridAsyncDemoMVVM/RemoteOrDbDataItem.cs | 27 ++ .../RemoteOrDbDataSourceAsyncProxy.cs | 128 +++++++++ .../RemoteOrDbDataSourceEmulation.cs | 263 ++++++++++++++++++ .../filtersort/DescriptionList.cs | 72 +++++ .../filtersort/FilterDescription.cs | 14 + .../filtersort/FilterDescriptionList.cs | 12 + .../filtersort/IFilterOrderDescription.cs | 7 + .../IFilteredSortedSourceProviderAsync.cs | 7 + .../filtersort/ParentOfTypeExtensions.cs | 112 ++++++++ .../filtersort/SortDescription.cs | 16 ++ .../filtersort/SortDescriptionList.cs | 6 + DataGridAsyncDemoMVVM/packages.config | 5 + 25 files changed, 1235 insertions(+), 2 deletions(-) create mode 100644 DataGridAsyncDemoMVVM/App.config create mode 100644 DataGridAsyncDemoMVVM/App.xaml create mode 100644 DataGridAsyncDemoMVVM/App.xaml.cs create mode 100644 DataGridAsyncDemoMVVM/DataGridAsyncDemoMVVM.csproj create mode 100644 DataGridAsyncDemoMVVM/MainViewModel.cs create mode 100644 DataGridAsyncDemoMVVM/MainWindow.xaml create mode 100644 DataGridAsyncDemoMVVM/MainWindow.xaml.cs create mode 100644 DataGridAsyncDemoMVVM/Properties/AssemblyInfo.cs create mode 100644 DataGridAsyncDemoMVVM/Properties/Resources.Designer.cs create mode 100644 DataGridAsyncDemoMVVM/Properties/Resources.resx create mode 100644 DataGridAsyncDemoMVVM/Properties/Settings.Designer.cs create mode 100644 DataGridAsyncDemoMVVM/Properties/Settings.settings create mode 100644 DataGridAsyncDemoMVVM/RemoteOrDbDataItem.cs create mode 100644 DataGridAsyncDemoMVVM/RemoteOrDbDataSourceAsyncProxy.cs create mode 100644 DataGridAsyncDemoMVVM/RemoteOrDbDataSourceEmulation.cs create mode 100644 DataGridAsyncDemoMVVM/filtersort/DescriptionList.cs create mode 100644 DataGridAsyncDemoMVVM/filtersort/FilterDescription.cs create mode 100644 DataGridAsyncDemoMVVM/filtersort/FilterDescriptionList.cs create mode 100644 DataGridAsyncDemoMVVM/filtersort/IFilterOrderDescription.cs create mode 100644 DataGridAsyncDemoMVVM/filtersort/IFilteredSortedSourceProviderAsync.cs create mode 100644 DataGridAsyncDemoMVVM/filtersort/ParentOfTypeExtensions.cs create mode 100644 DataGridAsyncDemoMVVM/filtersort/SortDescription.cs create mode 100644 DataGridAsyncDemoMVVM/filtersort/SortDescriptionList.cs create mode 100644 DataGridAsyncDemoMVVM/packages.config diff --git a/AlphaChiTech.Virtualization.sln b/AlphaChiTech.Virtualization.sln index 2646d8d..0351571 100644 --- a/AlphaChiTech.Virtualization.sln +++ b/AlphaChiTech.Virtualization.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 14 -VisualStudioVersion = 14.0.25420.1 +# Visual Studio 15 +VisualStudioVersion = 15.0.27004.2009 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataGridAsyncDemo", "DataGridAsyncDemo\DataGridAsyncDemo.csproj", "{B1235F30-C8A9-4A18-B870-A7F23F214039}" EndProject @@ -14,6 +14,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{90A3E4 EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AlphaChiTech.Virtualization.Net4", "AlphaChiTech.Virtualization.Net4\AlphaChiTech.Virtualization.Net4.csproj", "{ECEDC613-843A-4D9A-8123-BD9600C9118E}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DataGridAsyncDemoMVVM", "DataGridAsyncDemoMVVM\DataGridAsyncDemoMVVM.csproj", "{DE19AAA5-881C-48BE-A8E7-A8799F5C4BD3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -28,8 +30,15 @@ Global {ECEDC613-843A-4D9A-8123-BD9600C9118E}.Debug|Any CPU.Build.0 = Debug|Any CPU {ECEDC613-843A-4D9A-8123-BD9600C9118E}.Release|Any CPU.ActiveCfg = Release|Any CPU {ECEDC613-843A-4D9A-8123-BD9600C9118E}.Release|Any CPU.Build.0 = Release|Any CPU + {DE19AAA5-881C-48BE-A8E7-A8799F5C4BD3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {DE19AAA5-881C-48BE-A8E7-A8799F5C4BD3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {DE19AAA5-881C-48BE-A8E7-A8799F5C4BD3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {DE19AAA5-881C-48BE-A8E7-A8799F5C4BD3}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {D457F9E2-2C21-4C1F-93EA-EE4DAD2CA2E4} + EndGlobalSection EndGlobal diff --git a/DataGridAsyncDemoMVVM/App.config b/DataGridAsyncDemoMVVM/App.config new file mode 100644 index 0000000..7785bb0 --- /dev/null +++ b/DataGridAsyncDemoMVVM/App.config @@ -0,0 +1,7 @@ + + + + + + + \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/App.xaml b/DataGridAsyncDemoMVVM/App.xaml new file mode 100644 index 0000000..2a0b8b1 --- /dev/null +++ b/DataGridAsyncDemoMVVM/App.xaml @@ -0,0 +1,11 @@ + + + + + + diff --git a/DataGridAsyncDemoMVVM/App.xaml.cs b/DataGridAsyncDemoMVVM/App.xaml.cs new file mode 100644 index 0000000..38c44bd --- /dev/null +++ b/DataGridAsyncDemoMVVM/App.xaml.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Configuration; +using System.Data; +using System.Linq; +using System.Threading.Tasks; +using System.Windows; + +namespace DataGridAsyncDemoMVVM +{ + /// + /// Interaction logic for App.xaml + /// + public partial class App : Application + { + } +} diff --git a/DataGridAsyncDemoMVVM/DataGridAsyncDemoMVVM.csproj b/DataGridAsyncDemoMVVM/DataGridAsyncDemoMVVM.csproj new file mode 100644 index 0000000..98fa948 --- /dev/null +++ b/DataGridAsyncDemoMVVM/DataGridAsyncDemoMVVM.csproj @@ -0,0 +1,119 @@ + + + + + Debug + AnyCPU + {DE19AAA5-881C-48BE-A8E7-A8799F5C4BD3} + WinExe + DataGridAsyncDemoMVVM + DataGridAsyncDemoMVVM + v4.7 + 512 + {60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + 4 + true + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + ..\packages\System.Linq.Dynamic.1.0.7\lib\net40\System.Linq.Dynamic.dll + + + + + + + + + 4.0 + + + + + + + + MSBuild:Compile + Designer + + + + + + + + + + + + + + + MSBuild:Compile + Designer + + + App.xaml + Code + + + MainWindow.xaml + Code + + + + + Code + + + True + True + Resources.resx + + + True + Settings.settings + True + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + SettingsSingleFileGenerator + Settings.Designer.cs + + + + + + + + {ecedc613-843a-4d9a-8123-bd9600c9118e} + AlphaChiTech.Virtualization.Net4 + + + + \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/MainViewModel.cs b/DataGridAsyncDemoMVVM/MainViewModel.cs new file mode 100644 index 0000000..1a46b59 --- /dev/null +++ b/DataGridAsyncDemoMVVM/MainViewModel.cs @@ -0,0 +1,30 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using AlphaChiTech.Virtualization; + +namespace DataGridAsyncDemoMVVM +{ + class MainViewModel + { + private VirtualizingObservableCollection _myDataVirtualizedAsyncFilterSortObservableCollection = null; + private RemoteOrDbDataSourceAsyncProxy _myRemoteOrDbDataSourceAsyncProxy = null; + + public VirtualizingObservableCollection MyDataVirtualizedAsyncFilterSortObservableCollection + { + get + { + if (this._myDataVirtualizedAsyncFilterSortObservableCollection == null) + { + this._myRemoteOrDbDataSourceAsyncProxy = new RemoteOrDbDataSourceAsyncProxy(new RemoteOrDbDataSourceEmulation()); + this._myDataVirtualizedAsyncFilterSortObservableCollection = + new VirtualizingObservableCollection( + new PaginationManager(this._myRemoteOrDbDataSourceAsyncProxy, pageSize: 10, maxPages: 2)); + } + return this._myDataVirtualizedAsyncFilterSortObservableCollection; + } + } + } +} diff --git a/DataGridAsyncDemoMVVM/MainWindow.xaml b/DataGridAsyncDemoMVVM/MainWindow.xaml new file mode 100644 index 0000000..44430e3 --- /dev/null +++ b/DataGridAsyncDemoMVVM/MainWindow.xaml @@ -0,0 +1,50 @@ + + + + + + + + + + + + + + + diff --git a/DataGridAsyncDemoMVVM/MainWindow.xaml.cs b/DataGridAsyncDemoMVVM/MainWindow.xaml.cs new file mode 100644 index 0000000..49a6ab5 --- /dev/null +++ b/DataGridAsyncDemoMVVM/MainWindow.xaml.cs @@ -0,0 +1,42 @@ +#region + +using System; +using System.Diagnostics; +using System.Windows; +using System.Windows.Threading; +using AlphaChiTech.Virtualization; + +#endregion + +namespace DataGridAsyncDemoMVVM +{ + #region + + #endregion + + /// + /// Interaction logic for MainWindow.xaml + /// + public partial class MainWindow : Window + { + public MainWindow() + { + //this routine only needs to run once, so first check to make sure the + //VirtualizationManager isn’t already initialized + if (!VirtualizationManager.IsInitialized) + { + //set the VirtualizationManager’s UIThreadExcecuteAction. In this case + //we’re using Dispatcher.Invoke to give the VirtualizationManager access + //to the dispatcher thread, and using a DispatcherTimer to run the background + //operations the VirtualizationManager needs to run to reclaim pages and manage memory. + VirtualizationManager.Instance.UIThreadExcecuteAction = a => Application.Current.Dispatcher.Invoke(a); + new DispatcherTimer(TimeSpan.FromMilliseconds(10), + DispatcherPriority.Background, + delegate { VirtualizationManager.Instance.ProcessActions(); }, + this.Dispatcher).Start(); + } + + this.InitializeComponent(); + } + } +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/Properties/AssemblyInfo.cs b/DataGridAsyncDemoMVVM/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..215acf3 --- /dev/null +++ b/DataGridAsyncDemoMVVM/Properties/AssemblyInfo.cs @@ -0,0 +1,53 @@ +using System.Reflection; +using System.Runtime.InteropServices; +using System.Windows; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("DataGridAsyncDemoMVVM")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("DataGridAsyncDemoMVVM")] +[assembly: AssemblyCopyright("Copyright © 2017")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +//In order to begin building localizable applications, set +//CultureYouAreCodingWith in your .csproj file +//inside a . For example, if you are using US english +//in your source files, set the to en-US. Then uncomment +//the NeutralResourceLanguage attribute below. Update the "en-US" in +//the line below to match the UICulture setting in the project file. + +//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)] + + +[assembly: ThemeInfo( + ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located + //(used if a resource is not found in the page, + // or application resource dictionaries) + ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located + //(used if a resource is not found in the page, + // app, or any theme specific resource dictionaries) +)] + + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/Properties/Resources.Designer.cs b/DataGridAsyncDemoMVVM/Properties/Resources.Designer.cs new file mode 100644 index 0000000..a4c20a8 --- /dev/null +++ b/DataGridAsyncDemoMVVM/Properties/Resources.Designer.cs @@ -0,0 +1,71 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DataGridAsyncDemoMVVM.Properties +{ + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources + { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() + { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager + { + get + { + if ((resourceMan == null)) + { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("DataGridAsyncDemoMVVM.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture + { + get + { + return resourceCulture; + } + set + { + resourceCulture = value; + } + } + } +} diff --git a/DataGridAsyncDemoMVVM/Properties/Resources.resx b/DataGridAsyncDemoMVVM/Properties/Resources.resx new file mode 100644 index 0000000..af7dbeb --- /dev/null +++ b/DataGridAsyncDemoMVVM/Properties/Resources.resx @@ -0,0 +1,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/Properties/Settings.Designer.cs b/DataGridAsyncDemoMVVM/Properties/Settings.Designer.cs new file mode 100644 index 0000000..6ae14ef --- /dev/null +++ b/DataGridAsyncDemoMVVM/Properties/Settings.Designer.cs @@ -0,0 +1,30 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace DataGridAsyncDemoMVVM.Properties +{ + + + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.0.0")] + internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase + { + + private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); + + public static Settings Default + { + get + { + return defaultInstance; + } + } + } +} diff --git a/DataGridAsyncDemoMVVM/Properties/Settings.settings b/DataGridAsyncDemoMVVM/Properties/Settings.settings new file mode 100644 index 0000000..c14891b --- /dev/null +++ b/DataGridAsyncDemoMVVM/Properties/Settings.settings @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/RemoteOrDbDataItem.cs b/DataGridAsyncDemoMVVM/RemoteOrDbDataItem.cs new file mode 100644 index 0000000..0d8c004 --- /dev/null +++ b/DataGridAsyncDemoMVVM/RemoteOrDbDataItem.cs @@ -0,0 +1,27 @@ +namespace DataGridAsyncDemoMVVM +{ + public class RemoteOrDbDataItem + { + public RemoteOrDbDataItem() + {} + + public RemoteOrDbDataItem( string name, string str1, string str2, int int1, double double1 ) + { + this.Name = name; + this.Str1 = str1; + this.Str2 = str2; + this.Int1 = int1; + this.Double1 = double1; + } + + #region properties + + public double Double1 { get; set; } + public int Int1 { get; set; } + public string Name { get; set; } + public string Str1 { get; set; } + public string Str2 { get; set; } + + #endregion + } +} diff --git a/DataGridAsyncDemoMVVM/RemoteOrDbDataSourceAsyncProxy.cs b/DataGridAsyncDemoMVVM/RemoteOrDbDataSourceAsyncProxy.cs new file mode 100644 index 0000000..a051998 --- /dev/null +++ b/DataGridAsyncDemoMVVM/RemoteOrDbDataSourceAsyncProxy.cs @@ -0,0 +1,128 @@ +using System; +using System.Linq; +using System.Threading.Tasks; +using AlphaChiTech.Virtualization; +using DataGridAsyncDemoMVVM.filtersort; + +namespace DataGridAsyncDemoMVVM +{ + #region + + #endregion + + /// + /// Remote/disk async data proxy. + /// Also add a delay on calls to simulate network/disk delay. + /// + public class RemoteOrDbDataSourceAsyncProxy + : IPagedSourceProviderAsync, IFilteredSortedSourceProviderAsync + { + #region fields + + private readonly RemoteOrDbDataSourceEmulation _remoteDatas; + + private readonly Random _rand = new Random(); + + #endregion + + public RemoteOrDbDataSourceAsyncProxy( RemoteOrDbDataSourceEmulation remoteDatas ) + { + this._remoteDatas = remoteDatas; + } + + #region properties + + + + public FilterDescriptionList FilterDescriptionList => this._remoteDatas.FilterDescriptionList; + + #endregion + + #region IFilteredSortedSourceProviderAsync Members + + public SortDescriptionList SortDescriptionList => this._remoteDatas.SortDescriptionList; + + #endregion + + #region IPagedSourceProvider Members (synchronous not available members) + + int IPagedSourceProvider.IndexOf( RemoteOrDbDataItem item ) + { + return this._remoteDatas.FilteredOrderedItems.IndexOf(item); + } + + public PagedSourceItemsPacket GetItemsAt( int pageoffset, int count, bool usePlaceholder ) + { + Task.Delay(50 + (int)Math.Round(this._rand.NextDouble() * 100)).Wait(); // Just to slow it down ! + return new PagedSourceItemsPacket + { + LoadedAt = DateTime.Now, + Items = (from items in this._remoteDatas.FilteredOrderedItems select items).Skip(pageoffset).Take(count) + }; + } + public int Count + { + get { + Task.Delay(20 + (int)Math.Round(this._rand.NextDouble() * 30)).Wait(); // Just to slow it down ! + return this._remoteDatas.FilteredOrderedItems.Count; ; } + } + + #endregion + + #region public members + + + + public Task GetCountAsync() + { + return Task.Run(() => + { + Task.Delay(20 + (int)Math.Round(this._rand.NextDouble() * 30)).Wait(); // Just to slow it down ! + return this._remoteDatas.FilteredOrderedItems.Count; + } ); + } + + public Task> GetItemsAtAsync( int pageoffset, int count, bool usePlaceholder ) + { + Console.WriteLine("Get"); + return Task.Run( () => + { + Task.Delay(50 + (int)Math.Round(this._rand.NextDouble() * 100)).Wait(); // Just to slow it down ! + return new PagedSourceItemsPacket + { + LoadedAt = DateTime.Now, + Items = ( from items in this._remoteDatas.FilteredOrderedItems select items ).Skip( pageoffset ).Take( count ) + }; + } ); + } + + public RemoteOrDbDataItem GetPlaceHolder( int index, int page, int offset ) + { + return new RemoteOrDbDataItem {Name = "Waiting [" + page + "/" + offset + "]"}; + } + + /// + /// This returns the index of a specific item. This method is optional – you can just return -1 if you + /// don’t need to use IndexOf. It’s not strictly required if don’t need to be able to seeking to a + /// specific item, but if you are selecting items implementing this method is recommended. + /// + /// + /// + public Task IndexOfAsync( RemoteOrDbDataItem item ) + { + return Task.Run( () => { return this._remoteDatas.FilteredOrderedItems.IndexOf( item ); } ); + } + + /// + /// This is a callback that runs when a Reset is called on a provider. Implementing this is also optional. + /// If you don’t need to do anything in particular when resets occur, you can leave this method body empty. + /// + /// + public void OnReset( int count ) + { + // Do nothing for now + } + + #endregion + } +} diff --git a/DataGridAsyncDemoMVVM/RemoteOrDbDataSourceEmulation.cs b/DataGridAsyncDemoMVVM/RemoteOrDbDataSourceEmulation.cs new file mode 100644 index 0000000..02ec279 --- /dev/null +++ b/DataGridAsyncDemoMVVM/RemoteOrDbDataSourceEmulation.cs @@ -0,0 +1,263 @@ +#region + + + +#endregion + +using System; +using System.Collections.Generic; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Text.RegularExpressions; +using DataGridAsyncDemoMVVM.filtersort; +using System.Linq; +using System.Linq.Dynamic; + +namespace DataGridAsyncDemoMVVM +{ + using SortDescription = filtersort.SortDescription; + + /// + /// Emulate a remote data repository (list of item + sort & filter values) + /// + public class RemoteOrDbDataSourceEmulation : IFilteredSortedSourceProviderAsync + { + #region statics + + //private static RemoteOrDbDataSourceEmulation _instance; + private static readonly object _syncRoot = new Object(); + + #endregion + + #region fields + + private readonly FilterDescriptionList _filterDescriptionList = new FilterDescriptionList(); + private readonly List _items = new List(); + private readonly List _orderedItems = new List(); + private readonly SortDescriptionList _sortDescriptionList = new SortDescriptionList(); + private bool _isFilteredItemsValid; + private string _orderByLinqExpression = ""; + private string _whereLinqExpression = ""; + + #endregion + + public RemoteOrDbDataSourceEmulation() + { + for ( int i = 0; i < 100000; i++ ) + { + this._items.Add( new RemoteOrDbDataItem( "Name_" + i, "Str1_" + i, "Str1_" + i, i, i ) ); + } + + this._sortDescriptionList.CollectionChanged += this.SortDescriptionListOnCollectionChanged; + this._filterDescriptionList.CollectionChanged += this.FilterDescriptionListOnCollectionChanged; + } + + #region properties + + public IList FilteredOrderedItems + { + get + { + if (this._isFilteredItemsValid) return this._orderedItems; + + lock (this) + { + this._orderedItems.Clear(); + + try + { + if ( string.IsNullOrWhiteSpace( this.WhereLinqExpression ) && string.IsNullOrWhiteSpace( this.OrderByLinqExpression ) ) + this._orderedItems.AddRange( this._items ); + else if ( !string.IsNullOrWhiteSpace( this.WhereLinqExpression ) && string.IsNullOrWhiteSpace( this.OrderByLinqExpression ) ) + this._orderedItems.AddRange( this._items.Where( this.WhereLinqExpression ) ); + else if ( string.IsNullOrWhiteSpace( this.WhereLinqExpression ) && !string.IsNullOrWhiteSpace( this.OrderByLinqExpression ) ) + this._orderedItems.AddRange( this._items.OrderBy( this.OrderByLinqExpression ) ); + else if ( !string.IsNullOrWhiteSpace( this.WhereLinqExpression ) && !string.IsNullOrWhiteSpace( this.OrderByLinqExpression ) ) + this._orderedItems.AddRange( this._items.Where( this.WhereLinqExpression ).OrderBy( this.OrderByLinqExpression ) ); + } + catch + { + } + this._isFilteredItemsValid = true; + } + return this._orderedItems; + } + } + + public string OrderByLinqExpression + { + get => this._orderByLinqExpression; + set + { + if ( !string.Equals( this._orderByLinqExpression, value ) ) + { + this._orderByLinqExpression = value; + this._isFilteredItemsValid = false; + } + } + } + + public string WhereLinqExpression + { + get => this._whereLinqExpression; + set + { + if ( !string.Equals( this._whereLinqExpression, value ) ) + { + this._whereLinqExpression = value; + this._isFilteredItemsValid = false; + } + } + } + + #endregion + + #region public members + + public void OrderBy( string orderByExpression ) + { + if ( !string.Equals( orderByExpression, this.OrderByLinqExpression ) ) + this.OrderByLinqExpression = orderByExpression; + } + + public void Where( string whereExpression ) + { + if ( !string.Equals( whereExpression, this.WhereLinqExpression ) ) + this.WhereLinqExpression = whereExpression; + } + + #endregion + + #region filter & sort Descrioption list + + public SortDescriptionList SortDescriptionList => this._sortDescriptionList; + + public FilterDescriptionList FilterDescriptionList => this._filterDescriptionList; + + private void SortDescriptionListOnCollectionChanged( object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs ) + { + string sort = ""; + + bool sortFound = false; + foreach ( SortDescription sortDescription in this._sortDescriptionList ) + { + if ( sortFound ) + sort += ", "; + + sortFound = true; + + sort += sortDescription.PropertyName; + sort += ( sortDescription.Direction == ListSortDirection.Ascending ) ? " ASC" : " DESC"; + } + + //if ((!sortFound) && (!string.IsNullOrWhiteSpace( primaryKey ))) + // sort += primaryKey + " ASC"; + + this.OrderByLinqExpression = sort; + } + + private void FilterDescriptionListOnCollectionChanged( object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs ) + { + if ( notifyCollectionChangedEventArgs.Action == NotifyCollectionChangedAction.Reset ) + { + string filter = ""; + + bool filterFound = false; + foreach ( FilterDescription filterDescription in this._filterDescriptionList ) + { + string subFilter = GetLinqQueryString( filterDescription ); + if ( !string.IsNullOrWhiteSpace( subFilter ) ) + { + if ( filterFound ) + filter += " and "; + filterFound = true; + filter += " " + subFilter + " "; + } + } + + this.WhereLinqExpression = filter; + } + } + + #region query builder + + private static readonly Regex _regexSplit = new Regex( @"(and)|(or)|(==)|(<>)|(!=)|(<=)|(>=)|(&&)|(\|\|)|(=)|(>)|(<)|(\*[\-_a-zA-Z0-9]+)|([\-_a-zA-Z0-9]+\*)|([\-_a-zA-Z0-9]+)", + RegexOptions.IgnoreCase ); + + private static readonly Regex _regexOp = new Regex( @"(and)|(or)|(==)|(<>)|(!=)|(<=)|(>=)|(&&)|(\|\|)|(=)|(>)|(<)", RegexOptions.IgnoreCase ); + private static readonly Regex _regexComparOp = new Regex( @"(==)|(<>)|(!=)|(<=)|(>=)|(=)|(>)|(<)", RegexOptions.None ); + + private static string GetLinqQueryString( FilterDescription filterDescription ) + { + string ret = ""; + + if ( !string.IsNullOrWhiteSpace( filterDescription.Filter ) ) + { + // using user str + linq.dynamic + try + { + // xceed syntax : empty (contains), AND (uppercase), OR (uppercase), <>, * (end with), =, >, >=, <, <=, * (start with) + // see http://doc.xceedsoft.com/products/XceedWpfDataGrid/Filter_Row.html + // linq.dynamic syntax : =, ==, <>, !=, <, >, <=, >=, &&, and, ||, or, x.m(…) (where x is the attrib and m the function (ex: Contains, StartsWith, EndsWith ...) + // see D:\DevC#\VirtualisingCollectionTest1\DynamicQuery\Dynamic Expressions.html + // ex : RemoteOrDbDataSourceEmulation.Instance.Items.Where( "Name.Contains(\"e_1\") or Name.Contains(\"e_2\")" ); + + string exp = filterDescription.Filter; + + // arrange expression + + bool previousTermIsOperator = false; + foreach ( Match match in _regexSplit.Matches( exp ) ) + { + if ( match.Success ) + { + //TODO processing results + if ( _regexOp.IsMatch( match.Value ) ) + { + if ( _regexComparOp.IsMatch( match.Value ) ) + { + // simple operator >, <, ==, != ... + ret += " " + filterDescription.PropertyName + " " + match.Value; + previousTermIsOperator = true; + } + else + { + // and, or ... + ret += " " + match.Value; + previousTermIsOperator = false; + } + } + else + { + // Value + if ( previousTermIsOperator ) + { + ret += " " + match.Value; + previousTermIsOperator = false; + } + else + { + if ( match.Value.StartsWith( "*" ) ) + ret += " " + filterDescription.PropertyName + ".EndsWith( \"" + match.Value.Substring( 1 ) + "\" )"; + else if ( match.Value.EndsWith( "*" ) ) + ret += " " + filterDescription.PropertyName + ".StartsWith( \"" + match.Value.Substring( 0, match.Value.Length - 1 ) + "\" )"; + else + ret += " " + filterDescription.PropertyName + ".Contains( \"" + match.Value + "\" )"; + previousTermIsOperator = false; + } + } + } + } + } + catch ( Exception ) + {} + } + + return ret; + } + + #endregion query builder + + #endregion filter & sort Descrioption list + } +} diff --git a/DataGridAsyncDemoMVVM/filtersort/DescriptionList.cs b/DataGridAsyncDemoMVVM/filtersort/DescriptionList.cs new file mode 100644 index 0000000..d88bb85 --- /dev/null +++ b/DataGridAsyncDemoMVVM/filtersort/DescriptionList.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Collections.Specialized; + +namespace DataGridAsyncDemoMVVM.filtersort +{ + public class DescriptionList : IEnumerable, IEnumerable, INotifyCollectionChanged + where T : IFilterOrderDescription + { + private readonly List _filterDescriptions = new List(); + + IEnumerator IEnumerable.GetEnumerator() + { + return this._filterDescriptions.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return this._filterDescriptions.GetEnumerator(); + } + + public event NotifyCollectionChangedEventHandler CollectionChanged; + + /// + /// If it exist, remove existing filter that apply on same property name. The add item arg at first position into filter list. + /// + /// + public void Add( T item ) + { + int index = this._filterDescriptions.FindIndex( description => description.PropertyName.Equals( item.PropertyName, StringComparison.Ordinal ) ); + if (index >= 0) + { + T removed = this._filterDescriptions[index]; + this._filterDescriptions.RemoveAt( index ); + //OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, removed, index ) ); + this._filterDescriptions.Insert( 0, item ); + //OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, item, 0 ) ); + + this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Move, removed, 0, index ) ); + } + else + { + this._filterDescriptions.Insert( 0, item ); + this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Add, item, 0 ) ); + } + } + + protected void OnCollectionChanged( NotifyCollectionChangedEventArgs arg ) + { + var evnt = this.CollectionChanged; + + if (evnt != null) + evnt( this, arg ); + } + + /// + /// If it exist, remove existing filter that apply on same property name. The add item arg at first position into filter list. + /// + /// + public void Remove( string propertyName ) + { + int index = this._filterDescriptions.FindIndex( description => description.PropertyName.Equals( propertyName, StringComparison.Ordinal ) ); + if (index >= 0) + { + T removed = this._filterDescriptions[index]; + this._filterDescriptions.RemoveAt( index ); + this.OnCollectionChanged( new NotifyCollectionChangedEventArgs( NotifyCollectionChangedAction.Remove, removed, index ) ); + } + } + } +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/filtersort/FilterDescription.cs b/DataGridAsyncDemoMVVM/filtersort/FilterDescription.cs new file mode 100644 index 0000000..5957684 --- /dev/null +++ b/DataGridAsyncDemoMVVM/filtersort/FilterDescription.cs @@ -0,0 +1,14 @@ +namespace DataGridAsyncDemoMVVM.filtersort +{ + public class FilterDescription : IFilterOrderDescription + { + public FilterDescription(string propertyName, string filter) + { + this.PropertyName = propertyName; + this.Filter = filter; + } + + public string Filter { get; set; } + public string PropertyName { get; set; } + } +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/filtersort/FilterDescriptionList.cs b/DataGridAsyncDemoMVVM/filtersort/FilterDescriptionList.cs new file mode 100644 index 0000000..b2b0ff4 --- /dev/null +++ b/DataGridAsyncDemoMVVM/filtersort/FilterDescriptionList.cs @@ -0,0 +1,12 @@ +using System.Collections.Specialized; + +namespace DataGridAsyncDemoMVVM.filtersort +{ + public class FilterDescriptionList : DescriptionList + { + public void OnCollectionReset() + { + this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); + } + } +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/filtersort/IFilterOrderDescription.cs b/DataGridAsyncDemoMVVM/filtersort/IFilterOrderDescription.cs new file mode 100644 index 0000000..6d91312 --- /dev/null +++ b/DataGridAsyncDemoMVVM/filtersort/IFilterOrderDescription.cs @@ -0,0 +1,7 @@ +namespace DataGridAsyncDemoMVVM.filtersort +{ + public interface IFilterOrderDescription + { + string PropertyName { get; set; } + } +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/filtersort/IFilteredSortedSourceProviderAsync.cs b/DataGridAsyncDemoMVVM/filtersort/IFilteredSortedSourceProviderAsync.cs new file mode 100644 index 0000000..0131f5e --- /dev/null +++ b/DataGridAsyncDemoMVVM/filtersort/IFilteredSortedSourceProviderAsync.cs @@ -0,0 +1,7 @@ +namespace DataGridAsyncDemoMVVM.filtersort +{ + public interface IFilteredSortedSourceProviderAsync + { + SortDescriptionList SortDescriptionList { get; } + } +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/filtersort/ParentOfTypeExtensions.cs b/DataGridAsyncDemoMVVM/filtersort/ParentOfTypeExtensions.cs new file mode 100644 index 0000000..1933f2b --- /dev/null +++ b/DataGridAsyncDemoMVVM/filtersort/ParentOfTypeExtensions.cs @@ -0,0 +1,112 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using System.Linq; +using System.Windows; +using System.Windows.Media; + +namespace DataGridAsyncDemoMVVM.filtersort +{ + internal static class ArgumentVerificationExtensions + { + public static void TestNotNull(this object parameter, string parameterName) + { + if (parameter == null) + throw new ArgumentNullException(parameterName); + } + + public static void TestNotEmptyString(this string parameter, string parameterName) + { + if (string.IsNullOrEmpty(parameter)) + throw new ArgumentException( + string.Format("The parameter '{0}' should not be empty string.", parameterName), parameterName); + } + } + + /// + /// Contains extension methods for enumerating the parents of an element. + /// + public static class ParentOfTypeExtensions + { + /// + /// Gets the parent element from the visual tree by given type. + /// + public static T ParentOfType(this DependencyObject element) where T : DependencyObject + { + if (element == null) + return null; + + return element.GetParents().OfType().FirstOrDefault(); + } + + + /// + /// Determines whether the element is an ancestor of the descendant. + /// + /// true if the visual object is an ancestor of descendant; otherwise, false. + public static bool IsAncestorOf(this DependencyObject element, DependencyObject descendant) + { + element.TestNotNull("element"); + descendant.TestNotNull("descendant"); + + return descendant == element || descendant.GetParents().Contains(element); + } + + /// + /// Searches up in the visual tree for parent element of the specified type. + /// + /// + /// The type of the parent that will be searched up in the visual object hierarchy. + /// The type should be . + /// + /// + /// The target which visual parents will be traversed. + /// + /// Visual parent of the specified type if there is any, otherwise null. + [SuppressMessage("Microsoft.Design", "CA1004:GenericMethodsShouldProvideTypeParameter")] + public static T GetVisualParent(this DependencyObject element) where T : DependencyObject + { + return element.ParentOfType(); + } + + /// + /// This recurses the visual tree for ancestors of a specific type. + /// + public static IEnumerable GetAncestors(this DependencyObject element) where T : class + { + return element.GetParents().OfType(); + } + + /// + /// This recurses the visual tree for a parent of a specific type. + /// + public static T GetParent(this DependencyObject element) where T : FrameworkElement + { + return element.ParentOfType(); + } + + /// + /// Enumerates through element's parents in the visual tree. + /// + public static IEnumerable GetParents(this DependencyObject element) + { + if (element == null) + throw new ArgumentNullException("element"); + + while ((element = element.GetParent()) != null) + yield return element; + } + + private static DependencyObject GetParent(this DependencyObject element) + { + var parent = VisualTreeHelper.GetParent(element); + if (parent == null) + { + var frameworkElement = element as FrameworkElement; + if (frameworkElement != null) + parent = frameworkElement.Parent; + } + return parent; + } + } +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/filtersort/SortDescription.cs b/DataGridAsyncDemoMVVM/filtersort/SortDescription.cs new file mode 100644 index 0000000..3d8374a --- /dev/null +++ b/DataGridAsyncDemoMVVM/filtersort/SortDescription.cs @@ -0,0 +1,16 @@ +using System.ComponentModel; + +namespace DataGridAsyncDemoMVVM.filtersort +{ + public class SortDescription : IFilterOrderDescription + { + public SortDescription(string propertyName, ListSortDirection? direction) + { + this.Direction = direction; + this.PropertyName = propertyName; + } + + public ListSortDirection? Direction { get; set; } + public string PropertyName { get; set; } + } +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/filtersort/SortDescriptionList.cs b/DataGridAsyncDemoMVVM/filtersort/SortDescriptionList.cs new file mode 100644 index 0000000..32ed9be --- /dev/null +++ b/DataGridAsyncDemoMVVM/filtersort/SortDescriptionList.cs @@ -0,0 +1,6 @@ +namespace DataGridAsyncDemoMVVM.filtersort +{ + public class SortDescriptionList : DescriptionList + { + } +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/packages.config b/DataGridAsyncDemoMVVM/packages.config new file mode 100644 index 0000000..a08ea93 --- /dev/null +++ b/DataGridAsyncDemoMVVM/packages.config @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file From 210fdba92a2732c245dc85d0320487b6c72d0fb6 Mon Sep 17 00:00:00 2001 From: Jan Pluskal Date: Sun, 17 Dec 2017 16:32:22 +0100 Subject: [PATCH 02/20] Add Filtering. --- DataGridAsyncDemoMVVM/App.xaml | 2 +- DataGridAsyncDemoMVVM/App.xaml.cs | 12 +- .../DataGridAsyncDemoMVVM.csproj | 17 + DataGridAsyncDemoMVVM/MainViewModel.cs | 58 ++- DataGridAsyncDemoMVVM/MainWindow.xaml | 27 +- DataGridAsyncDemoMVVM/MainWindow.xaml.cs | 1 + .../Properties/Resources.Designer.cs | 2 +- DataGridAsyncDemoMVVM/RemoteOrDbDataItem.cs | 43 +- .../RemoteOrDbDataSourceAsyncProxy.cs | 174 ++++---- .../RemoteOrDbDataSourceEmulation.cs | 401 +++++++++--------- ...ChangedEventArgsToDatagridHeaderAndText.cs | 33 ++ .../filtersort/DescriptionList.cs | 114 ++--- .../filtersort/MemberPathFilterText.cs | 8 + .../filtersort/ParentOfTypeExtensions.cs | 15 +- DataGridAsyncDemoMVVM/packages.config | 3 +- 15 files changed, 500 insertions(+), 410 deletions(-) create mode 100644 DataGridAsyncDemoMVVM/converters/TextChangedEventArgsToDatagridHeaderAndText.cs create mode 100644 DataGridAsyncDemoMVVM/filtersort/MemberPathFilterText.cs diff --git a/DataGridAsyncDemoMVVM/App.xaml b/DataGridAsyncDemoMVVM/App.xaml index 2a0b8b1..f90e982 100644 --- a/DataGridAsyncDemoMVVM/App.xaml +++ b/DataGridAsyncDemoMVVM/App.xaml @@ -8,4 +8,4 @@ - + \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/App.xaml.cs b/DataGridAsyncDemoMVVM/App.xaml.cs index 38c44bd..d71b991 100644 --- a/DataGridAsyncDemoMVVM/App.xaml.cs +++ b/DataGridAsyncDemoMVVM/App.xaml.cs @@ -1,17 +1,11 @@ -using System; -using System.Collections.Generic; -using System.Configuration; -using System.Data; -using System.Linq; -using System.Threading.Tasks; -using System.Windows; +using System.Windows; namespace DataGridAsyncDemoMVVM { /// - /// Interaction logic for App.xaml + /// Interaction logic for App.xaml /// public partial class App : Application { } -} +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/DataGridAsyncDemoMVVM.csproj b/DataGridAsyncDemoMVVM/DataGridAsyncDemoMVVM.csproj index 98fa948..76088dd 100644 --- a/DataGridAsyncDemoMVVM/DataGridAsyncDemoMVVM.csproj +++ b/DataGridAsyncDemoMVVM/DataGridAsyncDemoMVVM.csproj @@ -34,11 +34,26 @@ 4 + + ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.dll + + + ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Extras.dll + + + ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\GalaSoft.MvvmLight.Platform.dll + + + ..\packages\CommonServiceLocator.1.3\lib\portable-net4+sl5+netcore45+wpa81+wp8\Microsoft.Practices.ServiceLocation.dll + ..\packages\System.Linq.Dynamic.1.0.7\lib\net40\System.Linq.Dynamic.dll + + ..\packages\MvvmLightLibs.5.3.0.0\lib\net45\System.Windows.Interactivity.dll + @@ -57,6 +72,7 @@ MSBuild:Compile Designer + @@ -69,6 +85,7 @@ + MSBuild:Compile Designer diff --git a/DataGridAsyncDemoMVVM/MainViewModel.cs b/DataGridAsyncDemoMVVM/MainViewModel.cs index 1a46b59..7cfae0c 100644 --- a/DataGridAsyncDemoMVVM/MainViewModel.cs +++ b/DataGridAsyncDemoMVVM/MainViewModel.cs @@ -1,30 +1,54 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; +using System.ComponentModel; +using System.Diagnostics; +using System.Threading; using System.Threading.Tasks; +using System.Windows.Data; using AlphaChiTech.Virtualization; +using DataGridAsyncDemoMVVM.filtersort; +using GalaSoft.MvvmLight.Command; namespace DataGridAsyncDemoMVVM { - class MainViewModel + internal class MainViewModel { - private VirtualizingObservableCollection _myDataVirtualizedAsyncFilterSortObservableCollection = null; - private RemoteOrDbDataSourceAsyncProxy _myRemoteOrDbDataSourceAsyncProxy = null; + private readonly RemoteOrDbDataSourceAsyncProxy _myRemoteOrDbDataSourceAsyncProxy; + private VirtualizingObservableCollection myDataVirtualizedAsyncFilterSortObservableCollection; - public VirtualizingObservableCollection MyDataVirtualizedAsyncFilterSortObservableCollection + public MainViewModel() { - get + this._myRemoteOrDbDataSourceAsyncProxy = new RemoteOrDbDataSourceAsyncProxy(new RemoteOrDbDataSourceEmulation(100)); + this.myDataVirtualizedAsyncFilterSortObservableCollection = + new VirtualizingObservableCollection( + new PaginationManager(this._myRemoteOrDbDataSourceAsyncProxy, + pageSize: 10, maxPages: 2)); + this.MyDataVirtualizedAsyncFilterSortObservableCollectionCollectionView = + CollectionViewSource.GetDefaultView(myDataVirtualizedAsyncFilterSortObservableCollection); + + this.FilterCommand = new RelayCommand(async o => await this.Filter(o as MemberPathFilterText)); + } + + private int _filterWaitingCount = 0; + private async Task Filter(MemberPathFilterText memberPathFilterText) + { + if (String.IsNullOrWhiteSpace(memberPathFilterText.FilterText)) { - if (this._myDataVirtualizedAsyncFilterSortObservableCollection == null) - { - this._myRemoteOrDbDataSourceAsyncProxy = new RemoteOrDbDataSourceAsyncProxy(new RemoteOrDbDataSourceEmulation()); - this._myDataVirtualizedAsyncFilterSortObservableCollection = - new VirtualizingObservableCollection( - new PaginationManager(this._myRemoteOrDbDataSourceAsyncProxy, pageSize: 10, maxPages: 2)); - } - return this._myDataVirtualizedAsyncFilterSortObservableCollection; + this._myRemoteOrDbDataSourceAsyncProxy.FilterDescriptionList.Remove(memberPathFilterText + .ColumnSortMemberPath); } + else + { + this._myRemoteOrDbDataSourceAsyncProxy.FilterDescriptionList.Add(new FilterDescription(memberPathFilterText.ColumnSortMemberPath, memberPathFilterText.FilterText)); + } + Interlocked.Increment(ref this._filterWaitingCount); + await Task.Delay(500); + if (Interlocked.Decrement(ref this._filterWaitingCount) != 0) return; + this._myRemoteOrDbDataSourceAsyncProxy.FilterDescriptionList.OnCollectionReset(); + this.myDataVirtualizedAsyncFilterSortObservableCollection.Clear(); } + + public ICollectionView MyDataVirtualizedAsyncFilterSortObservableCollectionCollectionView { get; } + + public RelayCommand FilterCommand { get; } } -} +} \ No newline at end of file diff --git a/DataGridAsyncDemoMVVM/MainWindow.xaml b/DataGridAsyncDemoMVVM/MainWindow.xaml index 44430e3..1508f5e 100644 --- a/DataGridAsyncDemoMVVM/MainWindow.xaml +++ b/DataGridAsyncDemoMVVM/MainWindow.xaml @@ -1,11 +1,17 @@  + DataContext="{StaticResource MainViewModel}"> + + + @@ -15,7 +21,7 @@ + ItemsSource="{Binding MyDataVirtualizedAsyncFilterSortObservableCollectionCollectionView}">