diff --git a/Filtration/Models/ItemFilterBlockGroup.cs b/Filtration/Models/ItemFilterBlockGroup.cs index 218123e..851542f 100644 --- a/Filtration/Models/ItemFilterBlockGroup.cs +++ b/Filtration/Models/ItemFilterBlockGroup.cs @@ -1,14 +1,21 @@ -using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.ComponentModel; +using System.Linq; +using System.Runtime.CompilerServices; +using Filtration.Annotations; namespace Filtration.Models { - internal class ItemFilterBlockGroup + internal class ItemFilterBlockGroup : INotifyPropertyChanged { + private bool? _isChecked; + private bool _reentrancyCheck; + public ItemFilterBlockGroup(string groupName, ItemFilterBlockGroup parent) { GroupName = groupName; ParentGroup = parent; - ChildGroups = new List(); + ChildGroups = new ObservableCollection(); } public override string ToString() @@ -32,6 +39,79 @@ namespace Filtration.Models public string GroupName { get; private set; } public ItemFilterBlockGroup ParentGroup { get; private set; } - public List ChildGroups { get; private set; } + public ObservableCollection ChildGroups { get; private set; } + + public bool? IsChecked + { + get + { + return _isChecked; + } + set + { + if (_isChecked != value) + { + if (_reentrancyCheck) + { + return; + } + _reentrancyCheck = true; + _isChecked = value; + UpdateCheckState(); + OnPropertyChanged(); + _reentrancyCheck = false; + } + } + } + + private void UpdateCheckState() + { + // update all children: + if (ChildGroups.Count != 0) + { + UpdateChildrenCheckState(); + } + + // update parent item + if (ParentGroup != null) + { + var parentIsChecked = ParentGroup.DetermineCheckState(); + ParentGroup.IsChecked = parentIsChecked; + } + } + + private void UpdateChildrenCheckState() + { + foreach (var childGroup in ChildGroups.Where(c => IsChecked != null)) + { + childGroup.IsChecked = IsChecked; + } + } + + private bool? DetermineCheckState() + { + var allChildrenChecked = ChildGroups.Count(x => x.IsChecked == true) == ChildGroups.Count; + if (allChildrenChecked) + { + return true; + } + + var allChildrenUnchecked = ChildGroups.Count(x => x.IsChecked == false) == ChildGroups.Count; + if (allChildrenUnchecked) + { + return false; + } + + return null; + } + + public event PropertyChangedEventHandler PropertyChanged; + + [NotifyPropertyChangedInvocator] + protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) + { + var handler = PropertyChanged; + if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName)); + } } } diff --git a/Filtration/Views/AvalonDock/AvalonDockWorkspaceView.xaml b/Filtration/Views/AvalonDock/AvalonDockWorkspaceView.xaml index bc00bb8..895f80c 100644 --- a/Filtration/Views/AvalonDock/AvalonDockWorkspaceView.xaml +++ b/Filtration/Views/AvalonDock/AvalonDockWorkspaceView.xaml @@ -10,7 +10,7 @@ xmlns:xcad="http://schemas.xceed.com/wpf/xaml/avalondock" xmlns:converters="clr-namespace:Filtration.Converters" mc:Ignorable="d" - d:DataContext="{d:DesignInstance Type=viewModels:AvalonDockWorkspaceViewModel}" + d:DataContext="{d:DesignInstance d:Type=viewModels:AvalonDockWorkspaceViewModel}" d:DesignHeight="300" d:DesignWidth="300"> diff --git a/Filtration/Views/AvalonDock/AvalonDockWorkspaceView.xaml.cs b/Filtration/Views/AvalonDock/AvalonDockWorkspaceView.xaml.cs new file mode 100644 index 0000000..b76a69f --- /dev/null +++ b/Filtration/Views/AvalonDock/AvalonDockWorkspaceView.xaml.cs @@ -0,0 +1,10 @@ +namespace Filtration.Views.AvalonDock +{ + public partial class AvalonDockWorkspaceView + { + public AvalonDockWorkspaceView() + { + InitializeComponent(); + } + } +} diff --git a/Filtration/Views/ToolPanes/BlockGroupBrowserView.xaml b/Filtration/Views/ToolPanes/BlockGroupBrowserView.xaml index 1085365..807cc16 100644 --- a/Filtration/Views/ToolPanes/BlockGroupBrowserView.xaml +++ b/Filtration/Views/ToolPanes/BlockGroupBrowserView.xaml @@ -16,7 +16,7 @@ - +