From eb2779fa2a4d83c1425b60a92c50b3a10eecee69 Mon Sep 17 00:00:00 2001 From: NaBian <836904362@qq.com> Date: Sun, 1 Aug 2021 18:34:10 +0800 Subject: [PATCH] add basic code --- .../Controls/Ribbon/Ribbon.cs | 274 ++++++++++++++++++ .../Controls/Ribbon/RibbonGroup.cs | 27 ++ .../Controls/Ribbon/RibbonTab.cs | 22 ++ .../Controls/Ribbon/RibbonTabHeader.cs | 7 + .../Ribbon/RibbonTabHeaderItemsControl.cs | 12 + .../Controls/Ribbon/RibbonTabHeadersPanel.cs | 7 + .../HandyControl_Shared.projitems | 9 + .../Styles/Base/TabControlBaseStyle.xaml | 2 +- .../Themes/Styles/Ribbon.xaml | 142 +++++++++ 9 files changed, 501 insertions(+), 1 deletion(-) create mode 100644 src/Shared/HandyControl_Shared/Controls/Ribbon/Ribbon.cs create mode 100644 src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonGroup.cs create mode 100644 src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTab.cs create mode 100644 src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeader.cs create mode 100644 src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeaderItemsControl.cs create mode 100644 src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeadersPanel.cs create mode 100644 src/Shared/HandyControl_Shared/Themes/Styles/Ribbon.xaml diff --git a/src/Shared/HandyControl_Shared/Controls/Ribbon/Ribbon.cs b/src/Shared/HandyControl_Shared/Controls/Ribbon/Ribbon.cs new file mode 100644 index 00000000..9fae196c --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Ribbon/Ribbon.cs @@ -0,0 +1,274 @@ +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 +{ + [TemplatePart(Name = TabHeaderItemsControl, Type = typeof(ItemsControl))] + public class Ribbon : Selector + { + private const string TabHeaderItemsControl = "PART_TabHeaderItemsControl"; + + private ItemsControl _tabHeaderItemsControl; + + private readonly ObservableCollection _tabHeaderItemsSource = new(); + + public Ribbon() + { + ItemContainerGenerator.StatusChanged += OnItemContainerGeneratorStatusChanged; + + AddHandler(SelectableItem.SelectedEvent, new RoutedEventHandler(OnTabHeaderSelected)); + } + + private void OnTabHeaderSelected(object sender, RoutedEventArgs e) + { + if (_tabHeaderItemsControl == null) + { + return; + } + + if (e.OriginalSource is not RibbonTabHeader tabHeader) + { + return; + } + + var selectedIndex = _tabHeaderItemsControl.ItemContainerGenerator.IndexFromContainer(tabHeader); + var currentSelectedIndex = SelectedIndex; + + if (currentSelectedIndex < 0 || SelectedIndex != selectedIndex) + { + SelectedIndex = selectedIndex; + } + } + + 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 + { + 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}) + { + _tabHeaderItemsControl.ItemsSource = _tabHeaderItemsSource; + } + + UpdateSelectedContent(); + } + + protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e) + { + base.OnItemsChanged(e); + + if (e.Action == NotifyCollectionChangedAction.Remove || + e.Action == NotifyCollectionChangedAction.Replace || + e.Action == NotifyCollectionChangedAction.Reset) + { + InitializeSelection(); + } + + if ((ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated || e.Action != NotifyCollectionChangedAction.Move) && + e.Action != NotifyCollectionChangedAction.Remove) + { + return; + } + + RefreshHeaderCollection(); + } + + protected override DependencyObject GetContainerForItemOverride() => new RibbonTab(); + + protected override bool IsItemItsOwnContainerOverride(object item) => item is RibbonTab; + + private void OnItemContainerGeneratorStatusChanged(object sender, EventArgs e) + { + if (ItemContainerGenerator.Status != GeneratorStatus.ContainersGenerated) + { + return; + } + + CoerceValue(Ribbon.IsMinimizedProperty); + InitializeSelection(); + RefreshHeaderCollection(); + } + + private int GetFirstVisibleTabIndex() + { + var count = Items.Count; + for (var index = 0; index < count; ++index) + { + if (ItemContainerGenerator.ContainerFromIndex(index) is RibbonTab {IsVisible: true}) + { + return index; + } + } + + return -1; + } + + private void InitializeSelection() + { + if (SelectedIndex >= 0 || Items.Count <= 0) + { + return; + } + + var firstVisibleTabIndex = GetFirstVisibleTabIndex(); + if (firstVisibleTabIndex < 0) + { + return; + } + + 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() + { + var itemsCount = Items.Count; + for (var index = 0; index < itemsCount; ++index) + { + object header = null; + if (ItemContainerGenerator.ContainerFromIndex(index) is RibbonTab ribbonTab) + { + header = ribbonTab.Header; + } + + header ??= CreateDefaultHeaderObject(); + + if (index >= _tabHeaderItemsSource.Count) + { + _tabHeaderItemsSource.Add(header); + } + else + { + _tabHeaderItemsSource[index] = header; + } + } + + var headerCount = _tabHeaderItemsSource.Count; + for (var index = 0; index < headerCount - itemsCount; ++index) + { + _tabHeaderItemsSource.RemoveAt(itemsCount); + } + } + + private class SingleSpaceObject + { + public override string ToString() => " "; + } + } +} diff --git a/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonGroup.cs b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonGroup.cs new file mode 100644 index 00000000..e433c2a5 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonGroup.cs @@ -0,0 +1,27 @@ +using System.Windows; +using System.Windows.Controls; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + public class RibbonGroup : HeaderedItemsControl + { + public static readonly DependencyProperty ShowLauncherButtonProperty = DependencyProperty.Register( + "ShowLauncherButton", typeof(bool), typeof(RibbonGroup), new PropertyMetadata(ValueBoxes.FalseBox)); + + public bool ShowLauncherButton + { + get => (bool) GetValue(ShowLauncherButtonProperty); + set => SetValue(ShowLauncherButtonProperty, value); + } + + public static readonly DependencyProperty ShowSplitterProperty = DependencyProperty.Register( + "ShowSplitter", typeof(bool), typeof(RibbonGroup), new PropertyMetadata(ValueBoxes.TrueBox)); + + public bool ShowSplitter + { + get => (bool) GetValue(ShowSplitterProperty); + set => SetValue(ShowSplitterProperty, value); + } + } +} diff --git a/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTab.cs b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTab.cs new file mode 100644 index 00000000..2df2ee7a --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTab.cs @@ -0,0 +1,22 @@ +using System.Windows; +using System.Windows.Controls; +using HandyControl.Data; + +namespace HandyControl.Controls +{ + public class RibbonTab : HeaderedItemsControl + { + public static readonly DependencyProperty IsSelectedProperty = DependencyProperty.Register( + "IsSelected", typeof(bool), typeof(RibbonTab), new PropertyMetadata(ValueBoxes.FalseBox)); + + public bool IsSelected + { + get => (bool) GetValue(IsSelectedProperty); + set => SetValue(IsSelectedProperty, value); + } + + 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 new file mode 100644 index 00000000..66d8d2f4 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeader.cs @@ -0,0 +1,7 @@ +namespace HandyControl.Controls +{ + public class RibbonTabHeader : SelectableItem + { + + } +} diff --git a/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeaderItemsControl.cs b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeaderItemsControl.cs new file mode 100644 index 00000000..588e2e35 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeaderItemsControl.cs @@ -0,0 +1,12 @@ +using System.Windows; +using System.Windows.Controls; + +namespace HandyControl.Controls +{ + public class RibbonTabHeaderItemsControl : ItemsControl + { + protected override DependencyObject GetContainerForItemOverride() => new RibbonTabHeader(); + + protected override bool IsItemItsOwnContainerOverride(object item) => item is RibbonTabHeader; + } +} diff --git a/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeadersPanel.cs b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeadersPanel.cs new file mode 100644 index 00000000..052a9b26 --- /dev/null +++ b/src/Shared/HandyControl_Shared/Controls/Ribbon/RibbonTabHeadersPanel.cs @@ -0,0 +1,7 @@ +namespace HandyControl.Controls +{ + public class RibbonTabHeadersPanel : SimpleStackPanel + { + + } +} diff --git a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems index 1ed903e5..02e54593 100644 --- a/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems +++ b/src/Shared/HandyControl_Shared/HandyControl_Shared.projitems @@ -72,6 +72,12 @@ + + + + + + @@ -385,6 +391,9 @@ Designer + + Designer + Designer diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Base/TabControlBaseStyle.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Base/TabControlBaseStyle.xaml index a7db8ae9..7bfd7433 100644 --- a/src/Shared/HandyControl_Shared/Themes/Styles/Base/TabControlBaseStyle.xaml +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Base/TabControlBaseStyle.xaml @@ -9,7 +9,7 @@ - + diff --git a/src/Shared/HandyControl_Shared/Themes/Styles/Ribbon.xaml b/src/Shared/HandyControl_Shared/Themes/Styles/Ribbon.xaml new file mode 100644 index 00000000..1a3e598a --- /dev/null +++ b/src/Shared/HandyControl_Shared/Themes/Styles/Ribbon.xaml @@ -0,0 +1,142 @@ + + + M878.3 392.1L631.9 145.7c-6.5-6.5-15-9.7-23.5-9.7s-17 3.2-23.5 9.7L423.8 306.9c-12.2-1.4-24.5-2-36.8-2-73.2 0-146.4 24.1-206.5 72.3-15.4 12.3-16.6 35.4-2.7 49.4l181.7 181.7-215.4 215.2c-2.6 2.6-4.3 6.1-4.6 9.8l-3.4 37.2c-0.9 9.4 6.6 17.4 15.9 17.4 0.5 0 1 0 1.5-0.1l37.2-3.4c3.7-0.3 7.2-2 9.8-4.6l215.4-215.4 181.7 181.7c6.5 6.5 15 9.7 23.5 9.7 9.7 0 19.3-4.2 25.9-12.4 56.3-70.3 79.7-158.3 70.2-243.4l161.1-161.1c12.9-12.8 12.9-33.8 0-46.8z + M0,0 8,0 8,1 1,1 1,8 0,8 M 3.7,3 8,7.3 8,4 9,4 9,9 4,9 4,8 7.3,8 3,3.7 + + + + + + + + + +