From c8c966c89715b8fb16b5b6f315819423c6dc9ef6 Mon Sep 17 00:00:00 2001 From: Johan Larsson Date: Fri, 25 Nov 2016 00:44:40 +0100 Subject: [PATCH] Three state sort as attached property. --- .../Gu.Wpf.DataGrid2D.Demo.csproj | 11 +++ Gu.Wpf.DataGrid2D.Demo/MainWindow.xaml | 4 + Gu.Wpf.DataGrid2D.Demo/ThreeStateSortItem.cs | 58 ++++++++++++ .../ThreeStateSortView.xaml | 16 ++++ .../ThreeStateSortView.xaml.cs | 15 +++ .../ThreeStateSortViewModel.cs | 20 ++++ Gu.Wpf.DataGrid2D/Gu.Wpf.DataGrid2D.csproj | 1 + Gu.Wpf.DataGrid2D/Sort.cs | 94 +++++++++++++++++++ 8 files changed, 219 insertions(+) create mode 100644 Gu.Wpf.DataGrid2D.Demo/ThreeStateSortItem.cs create mode 100644 Gu.Wpf.DataGrid2D.Demo/ThreeStateSortView.xaml create mode 100644 Gu.Wpf.DataGrid2D.Demo/ThreeStateSortView.xaml.cs create mode 100644 Gu.Wpf.DataGrid2D.Demo/ThreeStateSortViewModel.cs create mode 100644 Gu.Wpf.DataGrid2D/Sort.cs diff --git a/Gu.Wpf.DataGrid2D.Demo/Gu.Wpf.DataGrid2D.Demo.csproj b/Gu.Wpf.DataGrid2D.Demo/Gu.Wpf.DataGrid2D.Demo.csproj index b38b9d7..d929dc1 100644 --- a/Gu.Wpf.DataGrid2D.Demo/Gu.Wpf.DataGrid2D.Demo.csproj +++ b/Gu.Wpf.DataGrid2D.Demo/Gu.Wpf.DataGrid2D.Demo.csproj @@ -111,6 +111,13 @@ Array2DView.xaml + + ThreeStateSortView.xaml + + + ThreeStateSortView.xaml + + TransposedView.xaml @@ -166,6 +173,10 @@ Designer MSBuild:Compile + + Designer + MSBuild:Compile + Designer MSBuild:Compile diff --git a/Gu.Wpf.DataGrid2D.Demo/MainWindow.xaml b/Gu.Wpf.DataGrid2D.Demo/MainWindow.xaml index 930cb6b..4012b6d 100644 --- a/Gu.Wpf.DataGrid2D.Demo/MainWindow.xaml +++ b/Gu.Wpf.DataGrid2D.Demo/MainWindow.xaml @@ -41,5 +41,9 @@ + + + + \ No newline at end of file diff --git a/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortItem.cs b/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortItem.cs new file mode 100644 index 0000000..15f6b99 --- /dev/null +++ b/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortItem.cs @@ -0,0 +1,58 @@ +namespace Gu.Wpf.DataGrid2D.Demo +{ + using System.ComponentModel; + using System.Runtime.CompilerServices; + using JetBrains.Annotations; + + public class ThreeStateSortItem : INotifyPropertyChanged + { + private string stringValue; + private int intValue; + + public event PropertyChangedEventHandler PropertyChanged; + + public string StringValue + { + get + { + return this.stringValue; + } + + set + { + if (value == this.stringValue) + { + return; + } + + this.stringValue = value; + this.OnPropertyChanged(); + } + } + + public int IntValue + { + get + { + return this.intValue; + } + + set + { + if (value == this.intValue) + { + return; + } + + this.intValue = value; + this.OnPropertyChanged(); + } + } + + [NotifyPropertyChangedInvocator] + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); + } + } +} \ No newline at end of file diff --git a/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortView.xaml b/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortView.xaml new file mode 100644 index 0000000..d04092a --- /dev/null +++ b/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortView.xaml @@ -0,0 +1,16 @@ + + + + + + + diff --git a/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortView.xaml.cs b/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortView.xaml.cs new file mode 100644 index 0000000..ca77fe1 --- /dev/null +++ b/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortView.xaml.cs @@ -0,0 +1,15 @@ +namespace Gu.Wpf.DataGrid2D.Demo +{ + using System.Windows.Controls; + + /// + /// Interaction logic for ThreeStateSortView.xaml + /// + public partial class ThreeStateSortView : UserControl + { + public ThreeStateSortView() + { + this.InitializeComponent(); + } + } +} diff --git a/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortViewModel.cs b/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortViewModel.cs new file mode 100644 index 0000000..c5a7df6 --- /dev/null +++ b/Gu.Wpf.DataGrid2D.Demo/ThreeStateSortViewModel.cs @@ -0,0 +1,20 @@ +namespace Gu.Wpf.DataGrid2D.Demo +{ + using System.Collections.ObjectModel; + + public class ThreeStateSortViewModel + { + public ThreeStateSortViewModel() + { + this.Items = new ObservableCollection + { + new ThreeStateSortItem {StringValue = "a", IntValue = 1}, + new ThreeStateSortItem {StringValue = "c", IntValue = 4}, + new ThreeStateSortItem {StringValue = "d", IntValue = 2}, + new ThreeStateSortItem {StringValue = "b", IntValue = 3}, + }; + } + + public ObservableCollection Items { get; } + } +} \ No newline at end of file diff --git a/Gu.Wpf.DataGrid2D/Gu.Wpf.DataGrid2D.csproj b/Gu.Wpf.DataGrid2D/Gu.Wpf.DataGrid2D.csproj index fbce9d3..80fc201 100644 --- a/Gu.Wpf.DataGrid2D/Gu.Wpf.DataGrid2D.csproj +++ b/Gu.Wpf.DataGrid2D/Gu.Wpf.DataGrid2D.csproj @@ -66,6 +66,7 @@ + diff --git a/Gu.Wpf.DataGrid2D/Sort.cs b/Gu.Wpf.DataGrid2D/Sort.cs new file mode 100644 index 0000000..017cab7 --- /dev/null +++ b/Gu.Wpf.DataGrid2D/Sort.cs @@ -0,0 +1,94 @@ +namespace Gu.Wpf.DataGrid2D +{ + using System; + using System.ComponentModel; + using System.Windows; + using System.Windows.Controls; + using System.Windows.Input; + + public class Sort + { + public static readonly DependencyProperty ThreeStateProperty = DependencyProperty.RegisterAttached( + "ThreeState", + typeof(bool), + typeof(Sort), + new PropertyMetadata(default(bool), OnThreeStateChanged)); + + private static readonly DependencyProperty SubscriptionProperty = DependencyProperty.RegisterAttached( + "Subscription", + typeof(SortingSubscription), + typeof(Sort), + new PropertyMetadata(default(SortingSubscription))); + + public static void SetThreeState(DependencyObject element, bool value) + { + element.SetValue(ThreeStateProperty, value); + } + + public static bool GetThreeState(DependencyObject element) + { + return (bool)element.GetValue(ThreeStateProperty); + } + + private static void OnThreeStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if ((bool)e.NewValue) + { + d.SetCurrentValue(SubscriptionProperty, new SortingSubscription((DataGrid)d)); + } + else + { + (d.GetValue(SubscriptionProperty) as IDisposable)?.Dispose(); + d.ClearValue(SubscriptionProperty); + } + } + + private static void OnDataGridSorting(object sender, DataGridSortingEventArgs e) + { + var dataGrid = (DataGrid)sender; + var sortPropertyName = e.Column.SortMemberPath; + if (!string.IsNullOrEmpty(sortPropertyName)) + { + // sorting is cleared when the previous state is Descending + if (e.Column.SortDirection.HasValue && e.Column.SortDirection.Value == ListSortDirection.Descending) + { + e.Column.SetCurrentValue(DataGridColumn.SortDirectionProperty, null); + if ((Keyboard.Modifiers & ModifierKeys.Shift) != ModifierKeys.Shift) + { + var sortDescriptions = dataGrid.Items.SortDescriptions; + for (var i = sortDescriptions.Count - 1; i >= 0; i--) + { + if (sortDescriptions[i].PropertyName == sortPropertyName) + { + sortDescriptions.RemoveAt(i); + } + } + } + else + { + dataGrid.Items.SortDescriptions.Clear(); + } + + dataGrid.Items.Refresh(); + e.Handled = true; + } + } + } + + private sealed class SortingSubscription : IDisposable + { + private readonly DataGrid dataGrid; + + public SortingSubscription(DataGrid dataGrid) + { + this.dataGrid = dataGrid; + this.dataGrid.Sorting += OnDataGridSorting; + } + + public void Dispose() + { + this.dataGrid.Sorting -= OnDataGridSorting; + } + } + } +}