From c6573a9e26b15823734f595a041f1274a440ef94 Mon Sep 17 00:00:00 2001 From: Bastian Schmidt Date: Sun, 10 Jan 2016 09:47:16 +0100 Subject: [PATCH] Adding start screen as mentioned in #242 --- Fluent.Ribbon.Showcase/TestContent.xaml | 39 ++++++++-- Fluent.Ribbon.Showcase/TestContent.xaml.cs | 6 ++ Fluent.Ribbon/Controls/Backstage.cs | 76 +++++++++++++----- Fluent.Ribbon/Controls/Ribbon.cs | 44 +++++++---- Fluent.Ribbon/Controls/StartScreen.cs | 67 ++++++++++++++++ .../Controls/StartScreenTabControl.cs | 48 ++++++++++++ .../Controls/WindowSteeringHelperControl.cs | 12 +-- Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj | 10 +++ Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj | 10 +++ Fluent.Ribbon/Themes/Generic/Common.xaml | 7 +- .../Themes/Generic/Controls/StartScreen.xaml | 16 ++++ .../Controls/StartScreenTabControl.xaml | 77 +++++++++++++++++++ Fluent.Ribbon/Themes/Office2010/Generic.txt | 2 + .../Themes/Office2013/Colors/ColorsWhite.xaml | 11 +-- .../Controls/BackstageTabControl.xaml | 4 +- Fluent.Ribbon/Themes/Office2013/Generic.txt | 2 + Fluent.Ribbon/Themes/Windows8/Generic.txt | 2 + 17 files changed, 378 insertions(+), 55 deletions(-) create mode 100644 Fluent.Ribbon/Controls/StartScreen.cs create mode 100644 Fluent.Ribbon/Controls/StartScreenTabControl.cs create mode 100644 Fluent.Ribbon/Themes/Generic/Controls/StartScreen.xaml create mode 100644 Fluent.Ribbon/Themes/Generic/Controls/StartScreenTabControl.xaml diff --git a/Fluent.Ribbon.Showcase/TestContent.xaml b/Fluent.Ribbon.Showcase/TestContent.xaml index 53c382ae7..98c9cd604 100644 --- a/Fluent.Ribbon.Showcase/TestContent.xaml +++ b/Fluent.Ribbon.Showcase/TestContent.xaml @@ -91,6 +91,30 @@ Visibility="Visible" /> + + + + + + + + + + + You can close the start screen by either clicking the button below or by pressing ESC + Close start screen + + + + + + @@ -355,10 +379,10 @@ Target="{Binding ElementName=RedoButton}" /> - + Use application menu - + + + Show start screen + diff --git a/Fluent.Ribbon.Showcase/TestContent.xaml.cs b/Fluent.Ribbon.Showcase/TestContent.xaml.cs index 1b13738cf..9e93c000a 100644 --- a/Fluent.Ribbon.Showcase/TestContent.xaml.cs +++ b/Fluent.Ribbon.Showcase/TestContent.xaml.cs @@ -421,6 +421,12 @@ private void OpenModalRibbonWindow_OnClick(object sender, RoutedEventArgs e) { new TestWindow().ShowDialog(); } + + private void ShowStartScreen_OnClick(object sender, RoutedEventArgs e) + { + this.startScreen.Shown = false; + this.startScreen.IsOpen = true; + } } public class TestRoutedCommand diff --git a/Fluent.Ribbon/Controls/Backstage.cs b/Fluent.Ribbon/Controls/Backstage.cs index ed12a270a..edc0a281a 100644 --- a/Fluent.Ribbon/Controls/Backstage.cs +++ b/Fluent.Ribbon/Controls/Backstage.cs @@ -36,8 +36,6 @@ public class Backstage : RibbonControl #region Properties - #region IsOpen - /// /// Gets or sets whether backstage is shown /// @@ -151,8 +149,6 @@ private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChange } } - #endregion - #region Content /// @@ -264,31 +260,33 @@ private void Click() private double savedWindowWidth = double.NaN; private double savedWindowHeight = double.NaN; - // Opens backstage on an Adorner layer - private void Show() + /// + /// Shows the + /// + protected virtual bool Show() { // don't open the backstage while in design mode if (DesignerProperties.GetIsInDesignMode(this)) { - return; + return false; } if (this.IsLoaded == false) { this.Loaded += this.OnDelayedShow; - return; + return false; } if (this.Content == null) { - return; + return false; } this.CreateAndAttachBackstageAdorner(); this.ShowAdorner(); - var ribbon = this.FindRibbon(); + var ribbon = this.GetParentRibbon(); if (ribbon != null) { ribbon.TabControl.IsDropDownOpen = false; @@ -336,6 +334,8 @@ private void Show() var content = this.Content as IInputElement; content?.Focus(); + + return true; } private void ShowAdorner() @@ -414,16 +414,38 @@ private void CreateAndAttachBackstageAdorner() if (topLevelElement == null) { return; - } + } - this.adorner = new BackstageAdorner(topLevelElement, this); + var layer = this.GetAdornerLayer(); - var layer = AdornerLayer.GetAdornerLayer(this); + this.adorner = new BackstageAdorner(topLevelElement, this); layer.Add(this.adorner); layer.CommandBindings.Add(new CommandBinding(RibbonCommands.OpenBackstage, HandleOpenBackstageCommandExecuted)); } + private AdornerLayer GetAdornerLayer() + { + var layer = AdornerLayer.GetAdornerLayer(this); + + if (layer == null) + { + var parentVisual = this.Parent as Visual ?? this.GetParentRibbon(); + + if (parentVisual != null) + { + layer = AdornerLayer.GetAdornerLayer(parentVisual); + } + } + + if (layer == null) + { + throw new Exception($"AdornerLayer could not be found for {this}."); + } + + return layer; + } + private static void HandleOpenBackstageCommandExecuted(object sender, ExecutedRoutedEventArgs args) { var target = ((BackstageAdorner)args.Source).Backstage; @@ -451,11 +473,13 @@ private void OnDelayedShow(object sender, EventArgs args) // Delaying show so everthing can load properly. // If we don't run this in the background setting IsOpen=true on application start we don't have access to the Bastage from the BackstageTabControl. - this.RunInDispatcherAsync(this.Show, DispatcherPriority.Background); + this.RunInDispatcherAsync(() => this.Show(), DispatcherPriority.Background); } - // Hide backstage - private void Hide() + /// + /// Hides the + /// + protected virtual void Hide() { this.Loaded -= this.OnDelayedShow; @@ -472,7 +496,7 @@ private void Hide() this.HideAdorner(); - var ribbon = this.FindRibbon(); + var ribbon = this.GetParentRibbon(); if (ribbon != null) { ribbon.TabControl.HighlightSelectedItem = true; @@ -522,8 +546,11 @@ private void Hide() this.collapsedElements.Clear(); } - // Finds underlying ribbon control - private Ribbon FindRibbon() + /// + /// Get the parent . + /// + /// The found or null of no parent could be found. + protected Ribbon GetParentRibbon() { DependencyObject item = this; @@ -533,6 +560,17 @@ private Ribbon FindRibbon() item = VisualTreeHelper.GetParent(item); } + if (item == null) + { + item = this; + + while (item != null && + item is Ribbon == false) + { + item = LogicalTreeHelper.GetParent(item); + } + } + return (Ribbon)item; } diff --git a/Fluent.Ribbon/Controls/Ribbon.cs b/Fluent.Ribbon/Controls/Ribbon.cs index 30f9d5634..2e9bdaded 100644 --- a/Fluent.Ribbon/Controls/Ribbon.cs +++ b/Fluent.Ribbon/Controls/Ribbon.cs @@ -450,16 +450,19 @@ public UIElement Menu /// This enables animation, styling, binding, etc... /// public static readonly DependencyProperty MenuProperty = - DependencyProperty.Register("Menu", typeof(UIElement), typeof(Ribbon), new UIPropertyMetadata(null, OnApplicationMenuChanged)); + DependencyProperty.Register(nameof(Menu), typeof(UIElement), typeof(Ribbon), new UIPropertyMetadata(null, AddOrRemoveLogicalChildOnPropertyChanged)); - static void OnApplicationMenuChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + #endregion + + public UIElement StartScreen { - Ribbon ribbon = (Ribbon)d; - if (e.OldValue != null) ribbon.RemoveLogicalChild(e.OldValue); - if (e.NewValue != null) ribbon.AddLogicalChild(e.NewValue); + get { return (UIElement)this.GetValue(StartScreenProperty); } + set { this.SetValue(StartScreenProperty, value); } } - #endregion + // Using a DependencyProperty as the backing store for StartScreen. This enables animation, styling, binding, etc... + public static readonly DependencyProperty StartScreenProperty = + DependencyProperty.Register(nameof(StartScreen), typeof(UIElement), typeof(UIElement), new UIPropertyMetadata(null, AddOrRemoveLogicalChildOnPropertyChanged)); /// /// Window title @@ -474,17 +477,13 @@ public string Title /// Using a DependencyProperty as the backing store for Title. This enables animation, styling, binding, etc... /// public static readonly DependencyProperty TitleProperty = - DependencyProperty.Register("Title", typeof(string), typeof(Ribbon), new UIPropertyMetadata("", OnTitleChanged)); + DependencyProperty.Register(nameof(Title), typeof(string), typeof(Ribbon), new UIPropertyMetadata(string.Empty, OnTitleChanged)); private static void OnTitleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { - var ribbon = d as Ribbon; + var ribbon = (Ribbon)d; - if (ribbon != null - && ribbon.TitleBar != null) - { - ribbon.TitleBar.InvalidateMeasure(); - } + ribbon?.TitleBar?.InvalidateMeasure(); } /// @@ -559,6 +558,20 @@ private static void OnSelectedTabIndexChanged(DependencyObject d, DependencyProp } } + private static void AddOrRemoveLogicalChildOnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + var ribbon = (Ribbon)d; + if (e.OldValue != null) + { + ribbon.RemoveLogicalChild(e.OldValue); + } + + if (e.NewValue != null) + { + ribbon.AddLogicalChild(e.NewValue); + } + } + /// /// Gets the first visible TabItem /// @@ -836,6 +849,11 @@ protected override IEnumerator LogicalChildren yield return this.Menu; } + if (this.StartScreen != null) + { + yield return this.StartScreen; + } + if (this.quickAccessToolBar != null) { yield return this.quickAccessToolBar; diff --git a/Fluent.Ribbon/Controls/StartScreen.cs b/Fluent.Ribbon/Controls/StartScreen.cs new file mode 100644 index 000000000..a5c34ab1e --- /dev/null +++ b/Fluent.Ribbon/Controls/StartScreen.cs @@ -0,0 +1,67 @@ +namespace Fluent +{ + using System.Windows; + + /// + /// Represents the container for the . + /// + public class StartScreen : Backstage + { + private bool previousTitleBarIsCollapsed; + + /// + /// Indicates whether the has aleaady been shown or not. + /// + public bool Shown + { + get { return (bool)this.GetValue(ShownProperty); } + set { this.SetValue(ShownProperty, value); } + } + + /// + /// for . + /// + public static readonly DependencyProperty ShownProperty = + DependencyProperty.Register(nameof(Shown), typeof(bool), typeof(StartScreen), new FrameworkPropertyMetadata(false, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, null)); + + static StartScreen() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(StartScreen), new FrameworkPropertyMetadata(typeof(StartScreen))); + } + + /// + /// Shows the . + /// + protected override bool Show() + { + var ribbon = this.GetParentRibbon(); + + if (ribbon?.TitleBar != null) + { + this.previousTitleBarIsCollapsed = ribbon.TitleBar.IsCollapsed; + ribbon.TitleBar.IsCollapsed = true; + } + + if (this.Shown) + { + return false; + } + + return this.Shown = base.Show(); + } + + /// + /// Hides the . + /// + protected override void Hide() + { + base.Hide(); + + var ribbon = this.GetParentRibbon(); + if (ribbon?.TitleBar != null) + { + ribbon.TitleBar.IsCollapsed = this.previousTitleBarIsCollapsed; + } + } + } +} \ No newline at end of file diff --git a/Fluent.Ribbon/Controls/StartScreenTabControl.cs b/Fluent.Ribbon/Controls/StartScreenTabControl.cs new file mode 100644 index 000000000..34d13ba35 --- /dev/null +++ b/Fluent.Ribbon/Controls/StartScreenTabControl.cs @@ -0,0 +1,48 @@ +namespace Fluent +{ + using System.Windows; + + /// + /// Control for representing the left and right side of the start screen. + /// + public class StartScreenTabControl : BackstageTabControl + { + /// + /// Left side panel content of the startscreen. + /// + public object LeftContent + { + get { return (object)this.GetValue(LeftContentProperty); } + set { this.SetValue(LeftContentProperty, value); } + } + + /// + /// for . + /// + public static readonly DependencyProperty LeftContentProperty = + DependencyProperty.Register(nameof(LeftContent), typeof(object), typeof(StartScreenTabControl)); + + /// + /// Right side panel content of the startscreen. + /// + public object RightContent + { + get { return (object)this.GetValue(RightContentProperty); } + set { this.SetValue(RightContentProperty, value); } + } + + /// + /// for . + /// + public static readonly DependencyProperty RightContentProperty = + DependencyProperty.Register(nameof(RightContent), typeof(object), typeof(StartScreenTabControl)); + + /// + /// Static constructor. + /// + static StartScreenTabControl() + { + DefaultStyleKeyProperty.OverrideMetadata(typeof(StartScreenTabControl), new FrameworkPropertyMetadata(typeof(StartScreenTabControl))); + } + } +} \ No newline at end of file diff --git a/Fluent.Ribbon/Controls/WindowSteeringHelperControl.cs b/Fluent.Ribbon/Controls/WindowSteeringHelperControl.cs index 04ab06250..68e4192be 100644 --- a/Fluent.Ribbon/Controls/WindowSteeringHelperControl.cs +++ b/Fluent.Ribbon/Controls/WindowSteeringHelperControl.cs @@ -12,14 +12,14 @@ public class WindowSteeringHelperControl : Border { /// - /// Creates a new instance + /// Static constructor /// - public WindowSteeringHelperControl() + static WindowSteeringHelperControl() { - this.Background = Brushes.Transparent; - this.IsHitTestVisible = true; - this.HorizontalAlignment = HorizontalAlignment.Stretch; - this.VerticalAlignment = VerticalAlignment.Stretch; + BackgroundProperty.OverrideMetadata(typeof(WindowSteeringHelperControl), new FrameworkPropertyMetadata(Brushes.Transparent)); + IsHitTestVisibleProperty.OverrideMetadata(typeof(WindowSteeringHelperControl), new UIPropertyMetadata(true)); + HorizontalAlignmentProperty.OverrideMetadata(typeof(WindowSteeringHelperControl), new FrameworkPropertyMetadata(HorizontalAlignment.Stretch)); + VerticalAlignmentProperty.OverrideMetadata(typeof(WindowSteeringHelperControl), new FrameworkPropertyMetadata(VerticalAlignment.Stretch)); } /// diff --git a/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj b/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj index 7a89bd010..a816f8658 100644 --- a/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj +++ b/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj @@ -85,6 +85,7 @@ + @@ -180,6 +181,7 @@ + @@ -194,6 +196,14 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + MSBuild:Compile Designer diff --git a/Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj b/Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj index 8fa0c48f1..80c268088 100644 --- a/Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj +++ b/Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj @@ -85,6 +85,7 @@ + @@ -180,6 +181,7 @@ + @@ -194,6 +196,14 @@ Designer MSBuild:Compile + + MSBuild:Compile + Designer + + + Designer + MSBuild:Compile + MSBuild:Compile Designer diff --git a/Fluent.Ribbon/Themes/Generic/Common.xaml b/Fluent.Ribbon/Themes/Generic/Common.xaml index 6b2cd4873..d0cf90ad8 100644 --- a/Fluent.Ribbon/Themes/Generic/Common.xaml +++ b/Fluent.Ribbon/Themes/Generic/Common.xaml @@ -23,7 +23,12 @@ BasedOn="{StaticResource BackstageStyle}" /> + \ No newline at end of file diff --git a/Fluent.Ribbon/Themes/Generic/Controls/StartScreenTabControl.xaml b/Fluent.Ribbon/Themes/Generic/Controls/StartScreenTabControl.xaml new file mode 100644 index 000000000..ad56176c8 --- /dev/null +++ b/Fluent.Ribbon/Themes/Generic/Controls/StartScreenTabControl.xaml @@ -0,0 +1,77 @@ + + + + + + + \ No newline at end of file diff --git a/Fluent.Ribbon/Themes/Office2010/Generic.txt b/Fluent.Ribbon/Themes/Office2010/Generic.txt index 13ccc4298..a2c1b02e7 100644 --- a/Fluent.Ribbon/Themes/Office2010/Generic.txt +++ b/Fluent.Ribbon/Themes/Office2010/Generic.txt @@ -33,6 +33,8 @@ Office2010\Controls\InRibbonGallery.xaml Office2010\Controls\BackstageTabItem.xaml Office2010\Controls\BackstageControls.xaml Office2010\Controls\BackstageTabControl.xaml +Generic\Controls\StartScreen.xaml +Generic\Controls\StartScreenTabControl.xaml Office2010\Controls\RibbonSeparator.xaml Generic\Controls\RibbonToolBar.xaml Generic\Controls\RibbonToolBarControlGroup.xaml diff --git a/Fluent.Ribbon/Themes/Office2013/Colors/ColorsWhite.xaml b/Fluent.Ribbon/Themes/Office2013/Colors/ColorsWhite.xaml index 5eb4dd004..df67dafab 100644 --- a/Fluent.Ribbon/Themes/Office2013/Colors/ColorsWhite.xaml +++ b/Fluent.Ribbon/Themes/Office2013/Colors/ColorsWhite.xaml @@ -139,14 +139,9 @@ - - - - + + + Background="{TemplateBinding ItemsPanelBackground}">