using System.Collections.Generic; using System.ComponentModel; using System.Linq; using System.Runtime.CompilerServices; using System.Windows; using System.Windows.Controls; using JD.Rosetta.Module.ViewModel; using JetBrains.Annotations; using Ubisoft.Collections; namespace JD.Rosetta.Module.Controls { /// /// Interaction logic for CheckBoxList.xaml /// Feed it a collection of ItemCheckableViewModel /// public partial class CheckBoxList : UserControl, INotifyPropertyChanged { public event PropertyChangedEventHandler PropertyChanged; public CheckBoxList() { InitializeComponent(); Loaded += CheckBoxList_Loaded; } private void CheckBoxList_Loaded(object sender, RoutedEventArgs e) { AreAllBoxesCheckedOrUnchecked = AreAllBoxesCheckedAtStart; Loaded -= CheckBoxList_Loaded; // Avoid having the event called more than once, which unchecks previously checked boxes while loading } #region Dependency properties public static readonly DependencyProperty CheckOrUncheckAllBoxesTextProperty = DependencyProperty.Register("CheckOrUncheckAllBoxesText", typeof(string), typeof(CheckBoxList), new PropertyMetadata(string.Empty)); public string CheckOrUncheckAllBoxesText { get => (string) GetValue(CheckOrUncheckAllBoxesTextProperty); set => SetValue(CheckOrUncheckAllBoxesTextProperty, value); } public static readonly DependencyProperty ItemStatesProperty = DependencyProperty.Register("ItemStates", typeof(IEnumerable), typeof(CheckBoxList), new FrameworkPropertyMetadata(null)); public IEnumerable ItemStates { get => (IEnumerable) GetValue(ItemStatesProperty); set => SetValue(ItemStatesProperty, value); } public static readonly DependencyProperty AreAllBoxesCheckedAtStartProperty = DependencyProperty.Register("AreAllBoxesCheckedAtStart", typeof(bool), typeof(CheckBoxList), new PropertyMetadata(false)); public bool AreAllBoxesCheckedAtStart { get => (bool) GetValue(AreAllBoxesCheckedAtStartProperty); set => SetValue(AreAllBoxesCheckedAtStartProperty, value); } #endregion #region Checkboxes update logic private bool? _areAllBoxesCheckedOrUnchecked; public bool? AreAllBoxesCheckedOrUnchecked { get { if (ItemStates != null) { if (ItemStates.All(s => s.IsChecked)) _areAllBoxesCheckedOrUnchecked = true; else if (ItemStates.All(s => !s.IsChecked)) _areAllBoxesCheckedOrUnchecked = false; else _areAllBoxesCheckedOrUnchecked = null; } return _areAllBoxesCheckedOrUnchecked; } set { if (value == null) { value = false; } RefreshCheckBoxes(value); OnPropertyChanged(); } } private void ItemCheckBox_OnCheckedChanged(object sender, RoutedEventArgs e) { OnPropertyChanged(nameof(AreAllBoxesCheckedOrUnchecked)); } private void RefreshCheckBoxes(bool? checkOrUncheckAllBoxes) { if (checkOrUncheckAllBoxes != null) ItemStates.ForEach(l => l.IsChecked = (bool)checkOrUncheckAllBoxes); } #endregion #region UI layout logic public double MaxListHeight { get => GlobalStackPanel.ActualHeight - CheckOrUncheckAllBoxStackPanel.ActualHeight - GlobalStackPanel.Margin.Top - GlobalStackPanel.Margin.Bottom - CheckOrUncheckAllBoxStackPanel.Margin.Top - CheckOrUncheckAllBoxStackPanel.Margin.Bottom + 10; // Adding 10 seems to help for whatever reason } private void GlobalStackPanel_OnSizeChanged(object sender, SizeChangedEventArgs e) { if (e.HeightChanged) OnPropertyChanged(nameof(MaxListHeight)); } private void CheckOrUncheckAllBoxStackPanel_OnSizeChanged(object sender, SizeChangedEventArgs e) { if (e.HeightChanged) OnPropertyChanged(nameof(MaxListHeight)); } #endregion #region INotifyPropertyChanged implementation [NotifyPropertyChangedInvocator] protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } #endregion } }