From 522dc935b55c9783b98218b39762edebf87ea468 Mon Sep 17 00:00:00 2001 From: swety2003 Date: Mon, 12 Aug 2024 14:24:33 +0800 Subject: [PATCH 1/8] Move SettingsCard to a separate folder --- .../{ => SettingsCard}/SettingsCard.Properties.cs | 0 .../Controls/SettingsControls/{ => SettingsCard}/SettingsCard.cs | 0 .../SettingsControls/{ => SettingsCard}/SettingsCard.xaml | 0 .../{ => SettingsCard}/SettingsCardAutomationPeer.cs | 0 4 files changed, 0 insertions(+), 0 deletions(-) rename source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/{ => SettingsCard}/SettingsCard.Properties.cs (100%) rename source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/{ => SettingsCard}/SettingsCard.cs (100%) rename source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/{ => SettingsCard}/SettingsCard.xaml (100%) rename source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/{ => SettingsCard}/SettingsCardAutomationPeer.cs (100%) diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard.Properties.cs b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard/SettingsCard.Properties.cs similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard.Properties.cs rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard/SettingsCard.Properties.cs diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard.cs b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard/SettingsCard.cs similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard.cs rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard/SettingsCard.cs diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard.xaml b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard/SettingsCard.xaml similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard.xaml rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard/SettingsCard.xaml diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCardAutomationPeer.cs b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard/SettingsCardAutomationPeer.cs similarity index 100% rename from source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCardAutomationPeer.cs rename to source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsCard/SettingsCardAutomationPeer.cs From b2ffe2d5bdbc74c41795d79d50e27fabb46138f4 Mon Sep 17 00:00:00 2001 From: swety2003 Date: Mon, 12 Aug 2024 14:25:21 +0800 Subject: [PATCH 2/8] Add SettingsExpander --- .../SettingsExpander.Events.cs | 21 + .../SettingsExpander.ItemsControl.cs | 77 ++++ .../SettingsExpander.Properties.cs | 182 +++++++++ .../SettingsExpander/SettingsExpander.cs | 89 ++++ .../SettingsExpander/SettingsExpander.xaml | 385 ++++++++++++++++++ .../SettingsExpanderAutomationPeer.cs | 86 ++++ .../SettingsExpanderItemStyleSelector.cs | 49 +++ .../Themes/Generic.xaml | 3 +- 8 files changed, 891 insertions(+), 1 deletion(-) create mode 100644 source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.Events.cs create mode 100644 source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.ItemsControl.cs create mode 100644 source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.Properties.cs create mode 100644 source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.cs create mode 100644 source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.xaml create mode 100644 source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpanderAutomationPeer.cs create mode 100644 source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpanderItemStyleSelector.cs diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.Events.cs b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.Events.cs new file mode 100644 index 0000000..1fd22e5 --- /dev/null +++ b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.Events.cs @@ -0,0 +1,21 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace iNKORE.UI.WPF.Modern.Controls +{ + public partial class SettingsExpander + { + /// + /// Fires when the SettingsExpander is opened + /// + public event EventHandler? Expanded; + + /// + /// Fires when the expander is closed + /// + public event EventHandler? Collapsed; + } +} diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.ItemsControl.cs b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.ItemsControl.cs new file mode 100644 index 0000000..6c402de --- /dev/null +++ b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.ItemsControl.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows; + +namespace iNKORE.UI.WPF.Modern.Controls +{ + + //// Implement properties for ItemsControl like behavior. + public partial class SettingsExpander + { + public IList Items + { + get { return (IList)GetValue(ItemsProperty); } + set { SetValue(ItemsProperty, value); } + } + + public static readonly DependencyProperty ItemsProperty = + DependencyProperty.Register(nameof(Items), typeof(IList), typeof(SettingsExpander), new PropertyMetadata(null, OnItemsConnectedPropertyChanged)); + + public object ItemsSource + { + get { return (object)GetValue(ItemsSourceProperty); } + set { SetValue(ItemsSourceProperty, value); } + } + + public static readonly DependencyProperty ItemsSourceProperty = + DependencyProperty.Register(nameof(ItemsSource), typeof(object), typeof(SettingsExpander), new PropertyMetadata(null, OnItemsConnectedPropertyChanged)); + + public object ItemTemplate + { + get { return (object)GetValue(ItemTemplateProperty); } + set { SetValue(ItemTemplateProperty, value); } + } + + public static readonly DependencyProperty ItemTemplateProperty = + DependencyProperty.Register(nameof(ItemTemplate), typeof(object), typeof(SettingsExpander), new PropertyMetadata(null)); + + public StyleSelector ItemContainerStyleSelector + { + get { return (StyleSelector)GetValue(ItemContainerStyleSelectorProperty); } + set { SetValue(ItemContainerStyleSelectorProperty, value); } + } + + public static readonly DependencyProperty ItemContainerStyleSelectorProperty = + DependencyProperty.Register(nameof(ItemContainerStyleSelector), typeof(StyleSelector), typeof(SettingsExpander), new PropertyMetadata(null)); + + private static void OnItemsConnectedPropertyChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs args) + { + if (dependencyObject is SettingsExpander expander && expander._itemsRepeater is not null) + { + var datasource = expander.ItemsSource; + + if (datasource is null) + { + datasource = expander.Items; + } + + expander._itemsRepeater.ItemsSource = datasource; + } + } + + private void ItemsRepeater_ElementPrepared(ItemsRepeater sender, ItemsRepeaterElementPreparedEventArgs args) + { + if (ItemContainerStyleSelector != null && + args.Element is FrameworkElement element && + element.ReadLocalValue(FrameworkElement.StyleProperty) == DependencyProperty.UnsetValue) + { + // TODO: Get item from args.Index? + element.Style = ItemContainerStyleSelector.SelectStyle(null, element); + } + } + } +} diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.Properties.cs b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.Properties.cs new file mode 100644 index 0000000..af64e82 --- /dev/null +++ b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.Properties.cs @@ -0,0 +1,182 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows.Controls; +using System.Windows.Markup; +using System.Windows; + +namespace iNKORE.UI.WPF.Modern.Controls +{ + // Licensed to the .NET Foundation under one or more agreements. + // The .NET Foundation licenses this file to you under the MIT license. + // See the LICENSE file in the project root for more information. + + [ContentProperty(name:nameof(Content))] + public partial class SettingsExpander + { + /// + /// The backing for the property. + /// + public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register( + nameof(CornerRadius), typeof(CornerRadius), typeof(SettingsExpander), new PropertyMetadata(default(CornerRadius))); + + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty HeaderProperty = DependencyProperty.Register( + nameof(Header), + typeof(object), + typeof(SettingsExpander), + new PropertyMetadata(defaultValue: null)); + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty DescriptionProperty = DependencyProperty.Register( + nameof(Description), + typeof(object), + typeof(SettingsExpander), + new PropertyMetadata(defaultValue: null)); + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty HeaderIconProperty = DependencyProperty.Register( + nameof(HeaderIcon), + typeof(IconElement), + typeof(SettingsExpander), + new PropertyMetadata(defaultValue: null)); + + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty ContentProperty = DependencyProperty.Register( + nameof(Content), + typeof(object), + typeof(SettingsExpander), + new PropertyMetadata(defaultValue: null)); + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty ItemsHeaderProperty = DependencyProperty.Register( + nameof(ItemsHeader), + typeof(UIElement), + typeof(SettingsExpander), + new PropertyMetadata(defaultValue: null)); + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty ItemsFooterProperty = DependencyProperty.Register( + nameof(ItemsFooter), + typeof(UIElement), + typeof(SettingsExpander), + new PropertyMetadata(defaultValue: null)); + + /// + /// The backing for the property. + /// + public static readonly DependencyProperty IsExpandedProperty = DependencyProperty.Register( + nameof(IsExpanded), + typeof(bool), + typeof(SettingsExpander), + new PropertyMetadata(defaultValue: false, (d, e) => ((SettingsExpander)d).OnIsExpandedPropertyChanged((bool)e.OldValue, (bool)e.NewValue))); + + + /// + /// + /// + /// Gets or sets the CornerRadius. + /// + public CornerRadius CornerRadius + { + get { return (CornerRadius)GetValue(CornerRadiusProperty); } + set { SetValue(CornerRadiusProperty, value); } + } + + /// + /// + /// + /// Gets or sets the Header. + /// + public object Header + { + get => (object)GetValue(HeaderProperty); + set => SetValue(HeaderProperty, value); + } + + /// + /// Gets or sets the Description. + /// +#pragma warning disable CS0109 // Member does not hide an inherited member; new keyword is not required + public new object Description +#pragma warning restore CS0109 // Member does not hide an inherited member; new keyword is not required + { + get => (object)GetValue(DescriptionProperty); + set => SetValue(DescriptionProperty, value); + } + + /// + /// Gets or sets the HeaderIcon. + /// + public IconElement HeaderIcon + { + get => (IconElement)GetValue(HeaderIconProperty); + set => SetValue(HeaderIconProperty, value); + } + + /// + /// Gets or sets the Content. + /// + public object Content + { + get => (object)GetValue(ContentProperty); + set => SetValue(ContentProperty, value); + } + + /// + /// Gets or sets the ItemsFooter. + /// + public UIElement ItemsHeader + { + get => (UIElement)GetValue(ItemsHeaderProperty); + set => SetValue(ItemsHeaderProperty, value); + } + + /// + /// Gets or sets the ItemsFooter. + /// + public UIElement ItemsFooter + { + get => (UIElement)GetValue(ItemsFooterProperty); + set => SetValue(ItemsFooterProperty, value); + } + + /// + /// Gets or sets the IsExpanded state. + /// + public bool IsExpanded + { + get => (bool)GetValue(IsExpandedProperty); + set => SetValue(IsExpandedProperty, value); + } + protected virtual void OnIsExpandedPropertyChanged(bool oldValue, bool newValue) + { + OnIsExpandedChanged(oldValue, newValue); + + if (newValue) + { + Expanded?.Invoke(this, EventArgs.Empty); + } + else + { + Collapsed?.Invoke(this, EventArgs.Empty); + } + } + } +} diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.cs b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.cs new file mode 100644 index 0000000..83ece7d --- /dev/null +++ b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.cs @@ -0,0 +1,89 @@ +using System.Collections.Generic; +using System.Windows.Automation.Peers; +using System.Windows.Automation; +using System.Windows; + +namespace iNKORE.UI.WPF.Modern.Controls +{ + // Licensed to the .NET Foundation under one or more agreements. + // The .NET Foundation licenses this file to you under the MIT license. + // See the LICENSE file in the project root for more information. + + //// Note: ItemsRepeater will request all the available horizontal space: https://github.com/microsoft/microsoft-ui-xaml/issues/3842 + [TemplatePart(Name = PART_ItemsRepeater, Type = typeof(ItemsRepeater))] + [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(FrameworkElement))] + public partial class SettingsExpander : System.Windows.Controls.Control + { + private const string PART_ItemsRepeater = "PART_ItemsRepeater"; + + private ItemsRepeater? _itemsRepeater; + + /// + /// The SettingsExpander is a collapsable control to host multiple SettingsCards. + /// + public SettingsExpander() + { + this.DefaultStyleKey = typeof(SettingsExpander); + Items = new List(); + } + + /// + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + SetAccessibleName(); + + if (_itemsRepeater != null) + { + _itemsRepeater.ElementPrepared -= this.ItemsRepeater_ElementPrepared; + } + + _itemsRepeater = GetTemplateChild(PART_ItemsRepeater) as ItemsRepeater; + + if (_itemsRepeater != null) + { + _itemsRepeater.ElementPrepared += this.ItemsRepeater_ElementPrepared; + + // Update it's source based on our current items properties. + OnItemsConnectedPropertyChanged(this, new DependencyPropertyChangedEventArgs()); // Can't get it to accept type here? (DependencyPropertyChangedEventArgs)EventArgs.Empty + } + } + + private void SetAccessibleName() + { + if (string.IsNullOrEmpty(AutomationProperties.GetName(this))) + { + if (Header is string headerString && !string.IsNullOrEmpty(headerString)) + { + AutomationProperties.SetName(this, headerString); + } + } + } + + /// + /// Creates AutomationPeer + /// + /// An automation peer for . + protected override AutomationPeer OnCreateAutomationPeer() + { + return new SettingsExpanderAutomationPeer(this); + } + + private void OnIsExpandedChanged(bool oldValue, bool newValue) + { + var peer = FrameworkElementAutomationPeer.FromElement(this) as SettingsExpanderAutomationPeer; + peer?.RaiseExpandedChangedEvent(newValue); + } + + //protected override bool IsItemItsOwnContainerOverride(object item) + //{ + // return item is SettingsCard; + //} + + //protected override DependencyObject GetContainerForItemOverride() + //{ + // var item = new SettingsCard(); + // return item; + //} + } +} diff --git a/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.xaml b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.xaml new file mode 100644 index 0000000..206a5ed --- /dev/null +++ b/source/iNKORE.UI.WPF.Modern.Controls/Controls/SettingsControls/SettingsExpander/SettingsExpander.xaml @@ -0,0 +1,385 @@ + + + + + + + + Show all settings + 16,16,4,16 + 58,8,44,8 + 0,1,0,0 + 58,8,16,8 + 16 + 32 + 32 + + + + + + + + + + + + + + + + + + @@ -66,7 +59,7 @@ Background="{TemplateBinding Background}" BorderBrush="{DynamicResource ExpanderHeaderBorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" - CornerRadius="{TemplateBinding chelper:ControlHelper.CornerRadius}"> + CornerRadius="{TemplateBinding ui:ControlHelper.CornerRadius}"> @@ -166,6 +159,11 @@ + + + + +