From 41c661da1a3e3508f89f619cae52c39eaffa5ccf Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Mon, 2 Aug 2021 00:06:16 +0800 Subject: [PATCH] support for tab switching --- .../HandyControl_Net_40/Themes/Theme.xaml | 2 +- .../Controls/Ribbon/Ribbon.cs | 179 +++++------------- .../Controls/Ribbon/RibbonTab.cs | 73 ++++++- .../Controls/Ribbon/RibbonTabHeader.cs | 63 +++++- .../Themes/Styles/Ribbon.xaml | 5 +- 5 files changed, 186 insertions(+), 136 deletions(-) diff --git a/src/Net_40/HandyControl_Net_40/Themes/Theme.xaml b/src/Net_40/HandyControl_Net_40/Themes/Theme.xaml index 0ca52e76..f028b5e3 100644 --- a/src/Net_40/HandyControl_Net_40/Themes/Theme.xaml +++ b/src/Net_40/HandyControl_Net_40/Themes/Theme.xaml @@ -10867,7 +10867,7 @@ - + diff --git a/src/Shared/HandyControl_Shared/Controls/Ribbon/Ribbon.cs b/src/Shared/HandyControl_Shared/Controls/Ribbon/Ribbon.cs index 9fae196c..0578655b 100644 --- a/src/Shared/HandyControl_Shared/Controls/Ribbon/Ribbon.cs +++ b/src/Shared/HandyControl_Shared/Controls/Ribbon/Ribbon.cs @@ -1,12 +1,9 @@ using System; using System.Collections.ObjectModel; using System.Collections.Specialized; -using System.ComponentModel; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; -using System.Windows.Media; -using HandyControl.Data; namespace HandyControl.Controls { @@ -19,25 +16,48 @@ namespace HandyControl.Controls private readonly ObservableCollection _tabHeaderItemsSource = new(); + internal ItemsControl RibbonTabHeaderItemsControl => _tabHeaderItemsControl; + public Ribbon() { + SetRibbon(this, this); ItemContainerGenerator.StatusChanged += OnItemContainerGeneratorStatusChanged; - - AddHandler(SelectableItem.SelectedEvent, new RoutedEventHandler(OnTabHeaderSelected)); } - private void OnTabHeaderSelected(object sender, RoutedEventArgs e) + internal static readonly DependencyProperty RibbonProperty = DependencyProperty.RegisterAttached( + "Ribbon", typeof(Ribbon), typeof(Ribbon), + new FrameworkPropertyMetadata(default(Ribbon), FrameworkPropertyMetadataOptions.Inherits)); + + internal static void SetRibbon(DependencyObject element, Ribbon value) + => element.SetValue(RibbonProperty, value); + + internal static Ribbon GetRibbon(DependencyObject element) + => (Ribbon) element.GetValue(RibbonProperty); + + public override void OnApplyTemplate() + { + base.OnApplyTemplate(); + + _tabHeaderItemsControl = GetTemplateChild(TabHeaderItemsControl) as ItemsControl; + if (_tabHeaderItemsControl is {ItemsSource: null}) + { + _tabHeaderItemsControl.ItemsSource = _tabHeaderItemsSource; + } + } + + internal void ResetSelection() + { + SelectedIndex = -1; + InitializeSelection(); + } + + internal void NotifyMouseClickedOnTabHeader(RibbonTabHeader tabHeader) { if (_tabHeaderItemsControl == null) { return; } - if (e.OriginalSource is not RibbonTabHeader tabHeader) - { - return; - } - var selectedIndex = _tabHeaderItemsControl.ItemContainerGenerator.IndexFromContainer(tabHeader); var currentSelectedIndex = SelectedIndex; @@ -47,73 +67,14 @@ namespace HandyControl.Controls } } - private static readonly DependencyPropertyKey SelectedContentPropertyKey = - DependencyProperty.RegisterReadOnly("SelectedContent", typeof(object), typeof(Ribbon), - new FrameworkPropertyMetadata((object) null)); - - public static readonly DependencyProperty SelectedContentProperty = - SelectedContentPropertyKey.DependencyProperty; - - [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] - public object SelectedContent + internal void NotifyTabHeaderChanged() { - get => GetValue(SelectedContentProperty); - internal set => SetValue(SelectedContentPropertyKey, value); - } - - public static readonly DependencyProperty IsMinimizedProperty = DependencyProperty.Register(nameof(IsMinimized), - typeof(bool), typeof(Ribbon), - new PropertyMetadata(ValueBoxes.FalseBox, OnIsMinimizedChanged, CoerceIsMinimized)); - - private static object CoerceIsMinimized(DependencyObject d, object basevalue) - { - var num = (bool) basevalue ? 1 : 0; - var ribbon = (Ribbon) d; - return num != 0 && ribbon.ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated ? ValueBoxes.FalseBox : basevalue; - } - - private static void OnIsMinimizedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - - } - - public bool IsMinimized - { - get => (bool) GetValue(IsMinimizedProperty); - set => SetValue(IsMinimizedProperty, ValueBoxes.BooleanBox(value)); - } - - public static readonly DependencyProperty IsDropDownOpenProperty = - DependencyProperty.Register(nameof(IsDropDownOpen), typeof(bool), typeof(Ribbon), - new PropertyMetadata(ValueBoxes.FalseBox, OnIsDropDownOpenChanged, CoerceIsDropDownOpen)); - - private static object CoerceIsDropDownOpen(DependencyObject d, object basevalue) - { - return ValueBoxes.FalseBox; - } - - private static void OnIsDropDownOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) - { - - } - - public bool IsDropDownOpen - { - get => (bool) GetValue(IsDropDownOpenProperty); - set => SetValue(IsDropDownOpenProperty, ValueBoxes.BooleanBox(value)); - } - - public override void OnApplyTemplate() - { - base.OnApplyTemplate(); - - _tabHeaderItemsControl = GetTemplateChild(TabHeaderItemsControl) as ItemsControl; - if (_tabHeaderItemsControl is {ItemsSource: null}) + if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) { - _tabHeaderItemsControl.ItemsSource = _tabHeaderItemsSource; + return; } - UpdateSelectedContent(); + RefreshHeaderCollection(); } protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) @@ -140,6 +101,23 @@ namespace HandyControl.Controls protected override bool IsItemItsOwnContainerOverride(object item) => item is RibbonTab; + protected override void OnSelectionChanged(SelectionChangedEventArgs e) + { + base.OnSelectionChanged(e); + + if (e.AddedItems is not {Count: > 0}) + { + return; + } + + if (e.RemovedItems.Count > 0 && ItemContainerGenerator.ContainerFromItem(e.RemovedItems[0]) is RibbonTab oldRibbonTab) + { + oldRibbonTab.IsSelected = false; + } + + SelectedItem = e.AddedItems[0]; + } + private void OnItemContainerGeneratorStatusChanged(object sender, EventArgs e) { if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) @@ -147,7 +125,6 @@ namespace HandyControl.Controls return; } - CoerceValue(Ribbon.IsMinimizedProperty); InitializeSelection(); RefreshHeaderCollection(); } @@ -182,58 +159,6 @@ namespace HandyControl.Controls SelectedIndex = firstVisibleTabIndex; } - private static bool EqualsEx(object o1, object o2) - { - try - { - return Equals(o1, o2); - } - catch (InvalidCastException) - { - return false; - } - } - - private RibbonTab GetSelectedRibbonTab() - { - var selectedItem = SelectedItem; - if (selectedItem != null) - { - if (selectedItem is not RibbonTab ribbonTab) - { - ribbonTab = ItemContainerGenerator.ContainerFromIndex(SelectedIndex) as RibbonTab; - - if (ribbonTab == null || !EqualsEx(selectedItem, ItemContainerGenerator.ItemFromContainer(ribbonTab))) - { - ribbonTab = ItemContainerGenerator.ContainerFromItem(selectedItem) as RibbonTab; - } - } - - return ribbonTab; - } - - return null; - } - - private void UpdateSelectedContent() - { - if (SelectedIndex < 0) - { - SelectedContent = null; - return; - } - - var ribbonTab = GetSelectedRibbonTab(); - if (ribbonTab == null) - { - return; - } - - var visualParent = VisualTreeHelper.GetParent(ribbonTab) as FrameworkElement; - - //seitem - } - private static object CreateDefaultHeaderObject() => new SingleSpaceObject(); private void RefreshHeaderCollection() diff --git a/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTab.cs b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTab.cs index 2df2ee7a..1f5e3da6 100644 --- a/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTab.cs +++ b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTab.cs @@ -1,13 +1,58 @@ using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; using HandyControl.Data; +using HandyControl.Tools; namespace HandyControl.Controls { public class RibbonTab : HeaderedItemsControl { + public Ribbon Ribbon => Ribbon.GetRibbon(this); + + internal RibbonTabHeader RibbonTabHeader + { + get + { + var ribbon = Ribbon; + if (ribbon == null) + { + return null; + } + + var index = ribbon.ItemContainerGenerator.IndexFromContainer(this); + if (index < 0) + { + return null; + } + + var headerItemsControl = ribbon.RibbonTabHeaderItemsControl; + return headerItemsControl?.ItemContainerGenerator.ContainerFromIndex(index) as RibbonTabHeader; + } + } + + static RibbonTab() + { + VisibilityProperty.OverrideMetadata(typeof(RibbonTab), new PropertyMetadata(Visibility.Visible, OnVisibilityChanged)); + } + public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( - "IsSelected", typeof(bool), typeof(RibbonTab), new PropertyMetadata(ValueBoxes.FalseBox)); + "IsSelected", typeof(bool), typeof(RibbonTab), new PropertyMetadata(ValueBoxes.FalseBox, OnIsSelectedChanged)); + + private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbonTab = (RibbonTab) d; + if (ribbonTab.IsSelected) + { + ribbonTab.OnSelected(new RoutedEventArgs(Selector.SelectedEvent, ribbonTab)); + } + else + { + ribbonTab.OnUnselected(new RoutedEventArgs(Selector.UnselectedEvent, ribbonTab)); + } + + ribbonTab.RibbonTabHeader?.CoerceValue(RibbonTabHeader.IsSelectedProperty); + } public bool IsSelected { @@ -15,6 +60,32 @@ namespace HandyControl.Controls set => SetValue(IsSelectedProperty, value); } + protected virtual void OnSelected(RoutedEventArgs e) => RaiseEvent(e); + + protected virtual void OnUnselected(RoutedEventArgs e) => RaiseEvent(e); + + protected override void OnHeaderChanged(object oldHeader, object newHeader) + { + base.OnHeaderChanged(oldHeader, newHeader); + Ribbon?.NotifyTabHeaderChanged(); + } + + private static void OnVisibilityChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbonTab = (RibbonTab) d; + var ribbon = ribbonTab.Ribbon; + + if (ribbon == null || + !ribbonTab.IsSelected || + (Visibility) e.OldValue != Visibility.Visible || + (Visibility) e.NewValue == Visibility.Visible) + { + return; + } + + ribbon.ResetSelection(); + } + protected override DependencyObject GetContainerForItemOverride() => new RibbonGroup(); protected override bool IsItemItsOwnContainerOverride(object item) => item is RibbonGroup; diff --git a/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeader.cs b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeader.cs index 66d8d2f4..569668d0 100644 --- a/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeader.cs +++ b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeader.cs @@ -1,7 +1,62 @@ -namespace HandyControl.Controls -{ - public class RibbonTabHeader : SelectableItem - { +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using HandyControl.Data; +namespace HandyControl.Controls +{ + public class RibbonTabHeader : ContentControl + { + public Ribbon Ribbon => Ribbon.GetRibbon(this); + + internal RibbonTab RibbonTab + { + get + { + var itemsControl = ItemsControl.ItemsControlFromItemContainer(this); + var ribbon = Ribbon; + if (itemsControl == null || ribbon == null) + { + return null; + } + + var index = itemsControl.ItemContainerGenerator.IndexFromContainer(this); + return ribbon.ItemContainerGenerator.ContainerFromIndex(index) as RibbonTab; + } + } + + public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( + "IsSelected", typeof(bool), typeof(RibbonTabHeader), + new PropertyMetadata(ValueBoxes.FalseBox, OnIsSelectedChanged, CoerceIsSelected)); + + private static object CoerceIsSelected(DependencyObject d, object basevalue) + { + var ribbonTab = ((RibbonTabHeader) d).RibbonTab; + return ribbonTab != null ? ValueBoxes.BooleanBox(ribbonTab.IsSelected) : basevalue; + } + + private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + ((RibbonTabHeader) d).OnIsSelectedChanged((bool) e.OldValue, (bool) e.NewValue); + } + + public bool IsSelected + { + get => (bool) GetValue(IsSelectedProperty); + set => SetValue(IsSelectedProperty, value); + } + + protected virtual void OnIsSelectedChanged(bool oldIsSelected, bool newIsSelected) + { + + } + + protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) + { + base.OnMouseLeftButtonDown(e); + + Ribbon.NotifyMouseClickedOnTabHeader(this); + RibbonTab.IsSelected = true; + } } } diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Ribbon.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Ribbon.xaml index 1a3e598a..f5b2d876 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Ribbon.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Ribbon.xaml @@ -51,7 +51,6 @@ - @@ -85,7 +84,7 @@ - + @@ -112,7 +111,7 @@ - +