diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md
new file mode 100644
index 000000000..585d15e64
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE.md
@@ -0,0 +1,7 @@
+--
+### Environment
+
+- Fluent.Ribbon __v?.?.?__
+- Theme __?__
+- Windows __?__
+- .NET Framework __?.?__
diff --git a/.gitignore b/.gitignore
index ed296cee0..5e1c8efc9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -37,6 +37,7 @@ publish/
# Generated files
Fluent.Ribbon/Themes/**/Generic.xaml
packages/
+.tmp
# Allowed files
!Fluent.Ribbon/Themes/Generic.xaml
diff --git a/Changelog.md b/Changelog.md
index 850626692..fe4cae278 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -2,6 +2,9 @@
## 4.0.0 (preview)
+- ### Notices
+ - **As of now the Office 2010 and Windows 8 themes will be removed in version 5.0. You can vote for this at [Future direction of this library](../../issues/282).**
+
- ### Breaking changes
- New nuget dependency: [ControlzEx](https://www.nuget.org/packages/ControlzEx)
- BorderlessWindowBehavior was replaced by WindowChromeBehavior from [ControlzEx](https://github.com/ControlzEx/ControlzEx).
@@ -9,7 +12,7 @@
This behavior is initialized in code behind (InitializeWindowChromeBehavior) and shows which properties of RibbonWindow can be used to control the behavior.
- SaveWindowPosition and WindowSettingBehavior were removed [#196](../../issues/196)
- GlassBorderThickness was renamed to GlassFrameThickness to be consitent with WindowChrome and WindowChromeBehavior [#209](../../issues/209)
- - FluentTest project was renamed to Fluent.Showcase [#212](../../issues/212)
+ - FluentTest project was renamed to Fluent.Ribbon.Showcase [#212](../../issues/212)
- ### Development/Contributing changes
- We switched to Visual Studio 2015 so we can use nameof etc. [#219](../../issues/219)
@@ -35,20 +38,31 @@
- [#240](../../issues/240) - Backstage closes when popup is dismissed inside backstage
- [#241](../../issues/241) - Keytips should be cancelled if Alt+Num0 is pressed
- [#244](../../issues/244) - KeyTip not working for childs of ContentPresenter
- - [#246](../../issues/246) - Bind RibbonGroupBox.DataContext on QuickAccessToolBar
- - [#251](../../issues/251) - Changing RibbonStatusBar height to 23 and RibbonStatusBarItem foreground to BackstageFontBrush
+ - [#246](../../issues/246) - Bind RibbonGroupBox.DataContext on QuickAccessToolBar (thanks to @nishy2000)
+ - [#251](../../issues/251) - Changing RibbonStatusBar height to 23 and RibbonStatusBarItem foreground to BackstageFontBrush (thanks to @maurosampietro)
- [#254](../../issues/254) - Basic fix for KeyTips not working when focus is inside a WinForms control
- [#256](../../issues/256) - ComboBox items don't update properly on ItemsSource binding source collection changes
+ - [#255](../../issues/255) - Submenus don't show scroll viewer if items exceed the available space on screen (thanks to @floele-sp)
+ - [#257](../../issues/257) - Windows8 RibbonWindowTitleTextGlowBackground was missing (thanks to @maurosampietro)
+ - [#263](../../issues/263) - Changing theme from backstage is broken
+ - [#267](../../issues/267) - maximizing in Win 10
+ - [#269](../../issues/269) - Show underscore of header text on RibbonTabItem
+ - [#272](../../issues/272) - Changing RibbonThemeColorBrush does not change background of ItemsPanel in Backstage
+ - [#274](../../issues/274) - RadioButton Icon and LargeIcon
+ - [#280](../../issues/280) - Keytips of the Ribbon overlay StartScreen
+ - [#284](../../issues/284) - Overriding width of button does not work as it should
+ - [#285](../../issues/285) - MaterialDesign DialogHost issue with FluentRibbon
- OpenBackstage command was not acting on the correct backstage in a multiple backstage scenario (thanks to @maurosampietro)
- ### Enhancements
- - [#120](../../issues/120) - Adding short-cuts or additional information to Application Menu Item (How to improve)
+ - [#120](../../issues/120) - Adding short-cuts or additional information to Application Menu Item
- [#185](../../issues/185) - Major refactoring of how WindowChrome is used
- [#194](../../issues/194) - There should be an option to disable animations in the whole control
- [#205](../../issues/205) - Fluent Spinner handles Format="P0" incorrectly.
- [#207](../../issues/207) - Enable DragMove on unused RibbonTabControl space like in Office 2013
- - [#230](../../issues/230) - Option to disable the "Minimize"-Ribbon Button & Behavior
+ - [#230](../../issues/230) - Option to disable the "Minimize"-Ribbon Button & Behavior (thanks to @robertmuehsig)
- [#242](../../issues/242) - Add start screen like in office 2013 and upwards
+ - [#258](../../issues/258) - Refactoring of KeyTipService and KeyTipAdorner (merged with [#264](../../issues/264))
## 3.6.1
diff --git a/Dev.NuGet.Config b/Dev.NuGet.Config
new file mode 100644
index 000000000..3d6a5a7bf
--- /dev/null
+++ b/Dev.NuGet.Config
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Fluent.Ribbon.Showcase/TestContent.xaml b/Fluent.Ribbon.Showcase/TestContent.xaml
index 97f773cd8..c04eb542f 100644
--- a/Fluent.Ribbon.Showcase/TestContent.xaml
+++ b/Fluent.Ribbon.Showcase/TestContent.xaml
@@ -42,6 +42,17 @@
+
+
@@ -143,6 +154,47 @@
+
+
+
+
+ Office 2010 Silver
+ Office 2010 Black
+ Office 2010 Blue
+ Office 2013 White
+ Windows8 White
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
@@ -1249,6 +1292,7 @@
Icon="Images\Green.png"
LargeIcon="Images\GreenLarge.png">
- Test System.Windows.Controls.TextBox
+
+
+ Test System.Windows.Controls.TextBox
+
diff --git a/Fluent.Ribbon.Showcase/TestContent.xaml.cs b/Fluent.Ribbon.Showcase/TestContent.xaml.cs
index ebd69b48c..c0c4867d2 100644
--- a/Fluent.Ribbon.Showcase/TestContent.xaml.cs
+++ b/Fluent.Ribbon.Showcase/TestContent.xaml.cs
@@ -88,8 +88,8 @@ public Button CreateRibbonButton()
{
Command = fooCommand1.ItemCommand,
Header = "Foo",
- Icon = new BitmapImage(new Uri(@"Images\Green.png", UriKind.Relative)),
- LargeIcon = new BitmapImage(new Uri(@"Images\GreenLarge.png", UriKind.Relative)),
+ Icon = new BitmapImage(new Uri(@"pack://application:,,,/Fluent.Ribbon.Showcase;component/Images/Green.png", UriKind.Absolute)),
+ LargeIcon = new BitmapImage(new Uri(@"pack://application:,,,/Fluent.Ribbon.Showcase;component/Images/GreenLarge.png", UriKind.Absolute)),
};
this.CommandBindings.Add(fooCommand1.ItemCommandBinding);
diff --git a/Fluent.Ribbon.Showcase/ViewModels/ColorViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/ColorViewModel.cs
index f023769e9..a2b6c37f4 100644
--- a/Fluent.Ribbon.Showcase/ViewModels/ColorViewModel.cs
+++ b/Fluent.Ribbon.Showcase/ViewModels/ColorViewModel.cs
@@ -1,5 +1,6 @@
namespace FluentTest.ViewModels
{
+ using System.Windows;
using System.Windows.Media;
public class ColorViewModel : ViewModel
@@ -7,14 +8,10 @@ public class ColorViewModel : ViewModel
private Color standardColor;
private Color highlightColor;
- private readonly Color[] themeColors = { Colors.Red, Colors.Green, Colors.Blue, Colors.White, Colors.Black, Colors.Purple };
- private Color themeColor;
-
public ColorViewModel()
{
this.StandardColor = Colors.Black;
this.HighlightColor = Colors.Yellow;
- this.ThemeColor = Colors.Blue;
}
public Color StandardColor
@@ -23,7 +20,7 @@ public Color StandardColor
set
{
this.standardColor = value;
- this.OnPropertyChanged("StandardColor");
+ this.OnPropertyChanged(nameof(this.StandardColor));
}
}
@@ -33,22 +30,19 @@ public Color HighlightColor
set
{
this.highlightColor = value;
- this.OnPropertyChanged("HighlightColor");
+ this.OnPropertyChanged(nameof(this.HighlightColor));
}
}
- public Color[] ThemeColors
- {
- get { return this.themeColors; }
- }
+ public Color[] ThemeColors { get; } = { Colors.Red, Colors.Green, Colors.Blue, Colors.White, Colors.Black, Colors.Purple };
public Color ThemeColor
{
- get { return this.themeColor; }
+ get { return ((SolidColorBrush)Application.Current.Resources["RibbonThemeColorBrush"])?.Color ?? Colors.Pink; }
set
{
- this.themeColor = value;
- this.OnPropertyChanged("ThemeColor");
+ Application.Current.Resources["RibbonThemeColorBrush"] = new SolidColorBrush(value);
+ this.OnPropertyChanged(nameof(this.ThemeColor));
}
}
}
diff --git a/Fluent.Ribbon.Showcase/ViewModels/GalleryItemViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/GalleryItemViewModel.cs
index ff18d965a..abe9b1e97 100644
--- a/Fluent.Ribbon.Showcase/ViewModels/GalleryItemViewModel.cs
+++ b/Fluent.Ribbon.Showcase/ViewModels/GalleryItemViewModel.cs
@@ -1,15 +1,44 @@
namespace FluentTest.ViewModels
{
- public class GalleryItemViewModel
+ public class GalleryItemViewModel : ViewModel
{
+ private string text;
+ private string group;
+
public GalleryItemViewModel(string group, string text)
{
this.Group = group;
this.Text = text;
}
- public string Text { get; set; }
+ public string Text
+ {
+ get { return this.text; }
+
+ set
+ {
+ if (value == this.text)
+ {
+ return;
+ }
+ this.text = value;
+ this.OnPropertyChanged(nameof(this.Text));
+ }
+ }
- public string Group { get; set; }
+ public string Group
+ {
+ get { return this.group; }
+
+ set
+ {
+ if (value == this.group)
+ {
+ return;
+ }
+ this.group = value;
+ this.OnPropertyChanged(nameof(this.Group));
+ }
+ }
}
}
\ No newline at end of file
diff --git a/Fluent.Ribbon.Showcase/ViewModels/ViewModel.cs b/Fluent.Ribbon.Showcase/ViewModels/ViewModel.cs
index d6c113f4a..8c2b0757b 100644
--- a/Fluent.Ribbon.Showcase/ViewModels/ViewModel.cs
+++ b/Fluent.Ribbon.Showcase/ViewModels/ViewModel.cs
@@ -10,10 +10,7 @@ public class ViewModel : INotifyPropertyChanged
[NotifyPropertyChangedInvocator]
protected void OnPropertyChanged(string propertyName)
{
- if (this.PropertyChanged != null)
- {
- this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
- }
+ this.PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
\ No newline at end of file
diff --git a/Fluent.Ribbon.nuspec b/Fluent.Ribbon.nuspec
index 8712be561..946a9bd38 100644
--- a/Fluent.Ribbon.nuspec
+++ b/Fluent.Ribbon.nuspec
@@ -14,7 +14,7 @@
false
ribbon fluent ribbon ribbonwindow office2010 office2013 windows8 backstage
-
+
@@ -28,4 +28,4 @@
-
+
\ No newline at end of file
diff --git a/Fluent.Ribbon/Adorners/KeyTipAdorner.cs b/Fluent.Ribbon/Adorners/KeyTipAdorner.cs
index b1ad10722..c19685423 100644
--- a/Fluent.Ribbon/Adorners/KeyTipAdorner.cs
+++ b/Fluent.Ribbon/Adorners/KeyTipAdorner.cs
@@ -1,19 +1,15 @@
-using System;
-using System.Collections.Generic;
-using System.Diagnostics.CodeAnalysis;
-using System.Linq;
-using System.Windows;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Interop;
-using System.Windows.Media;
-using System.Windows.Threading;
-
-namespace Fluent
+namespace Fluent
{
+ using System;
+ using System.Collections.Generic;
using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Linq;
+ using System.Windows;
using System.Windows.Controls;
+ using System.Windows.Data;
+ using System.Windows.Documents;
+ using System.Windows.Media;
using Fluent.Internal;
///
@@ -299,58 +295,17 @@ public void Terminate()
this.Detach();
- if (this.parentAdorner != null)
- {
- this.parentAdorner.Terminate();
- }
+ this.parentAdorner?.Terminate();
- if (this.childAdorner != null)
- {
- this.childAdorner.Terminate();
- }
+ this.childAdorner?.Terminate();
- if (this.Terminated != null)
- {
- this.Terminated(this, EventArgs.Empty);
- }
+ this.Terminated?.Invoke(this, EventArgs.Empty);
this.Log("Termination");
}
#endregion
- #region Event Handlers
-
- //[SuppressMessage("Microsoft.Maintainability", "CA1502")]
- //private void OnPreviewKeyDown(object sender, KeyEventArgs e)
- //{
- // this.Log("Key Down {0} ({1})", e.Key, e.OriginalSource);
-
- // if (e.IsRepeat
- // || this.Visibility == Visibility.Hidden)
- // {
- // return;
- // }
-
- // if ((this.AdornedElement is ContextMenu == false && this.AdornedElement is MenuItem == false)
- // && ((e.Key == Key.Left)
- // || (e.Key == Key.Right)
- // || (e.Key == Key.Up)
- // || (e.Key == Key.Down)
- // || (e.Key == Key.Enter)
- // || (e.Key == Key.Tab)))
- // {
- // this.Visibility = Visibility.Hidden;
- // }
- // else if (e.Key == Key.Escape)
- // {
- // this.Back();
- // e.Handled = true;
- // }
- //}
-
- #endregion
-
#region Static Methods
private static AdornerLayer GetAdornerLayer(UIElement element)
@@ -398,10 +353,7 @@ private static UIElement GetTopLevelElement(UIElement element)
public void Back()
{
var control = this.keyTipElementContainer as IKeyTipedControl;
- if (control != null)
- {
- control.OnKeyTipBack();
- }
+ control?.OnKeyTipBack();
if (this.parentAdorner != null)
{
@@ -435,16 +387,10 @@ public bool Forward(string keys, bool click)
return true;
}
- // Forward to the next element
- private void Forward(UIElement element)
- {
- this.Forward(element, true);
- }
-
// Forward to the next element
private void Forward(UIElement element, bool click)
{
- this.Log("Forwarding");
+ this.Log("Forwarding to {0}", element);
this.Detach();
@@ -529,7 +475,7 @@ public bool ContainsKeyTipStartingWith(string keys)
// Hide / unhide keytips relative matching to entered keys
internal void FilterKeyTips(string keys)
{
- this.Log("FilterKeyTips");
+ this.Log("FilterKeyTips with {0}", keys);
// Backup current visibility of key tips
for (var i = 0; i < this.backupedVisibilities.Length; i++)
@@ -788,25 +734,17 @@ private void UpdateKeyTipPositions()
elementSize.Height / 2.0 + 2,
elementSize.Height / 2.0 + 2), this.AdornedElement);
}
- else if (this.associatedElements[i] is BackstageTabItem)
- {
- // BackstageButton Exclusive Placement
- var keyTipSize = this.keyTips[i].DesiredSize;
- var elementSize = this.associatedElements[i].DesiredSize;
- this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(
- new Point(
- 5,
- elementSize.Height / 2.0 - keyTipSize.Height), this.AdornedElement);
- }
else if (((FrameworkElement)this.associatedElements[i]).Parent is BackstageTabControl)
{
// Backstage Items Exclusive Placement
var keyTipSize = this.keyTips[i].DesiredSize;
var elementSize = this.associatedElements[i].DesiredSize;
- this.keyTipPositions[i] = this.associatedElements[i].TranslatePoint(
+ var parent = (UIElement)((FrameworkElement)this.associatedElements[i]).Parent;
+ var positionInParent = this.associatedElements[i].TranslatePoint(default(Point), parent);
+ this.keyTipPositions[i] = parent.TranslatePoint(
new Point(
- 20,
- elementSize.Height / 2.0 - keyTipSize.Height), this.AdornedElement);
+ 5,
+ positionInParent.Y + (elementSize.Height / 2.0 - keyTipSize.Height)), this.AdornedElement);
}
else
{
@@ -939,10 +877,11 @@ private void Log(string format, params object[] args)
var headeredControl = this.AdornedElement as IHeaderedControl;
if (headeredControl != null)
{
- name += string.Format(" ({0})", headeredControl.Header);
+ name += $" ({headeredControl.Header})";
}
- Debug.WriteLine("[" + name + "] " + string.Format(format, args), "KeyTipAdorner");
+ var formatted = string.Format(format, args);
+ Debug.WriteLine($"{$"[{name}] "}{formatted}", "KeyTipAdorner");
}
#endregion
diff --git a/Fluent.Ribbon/AttachedProperties/RibbonProperties.cs b/Fluent.Ribbon/AttachedProperties/RibbonProperties.cs
index 381ae511d..a8a5ec029 100644
--- a/Fluent.Ribbon/AttachedProperties/RibbonProperties.cs
+++ b/Fluent.Ribbon/AttachedProperties/RibbonProperties.cs
@@ -18,7 +18,7 @@ public class RibbonProperties
///
public static readonly DependencyProperty TitleBarHeightProperty =
DependencyProperty.RegisterAttached("TitleBarHeight", typeof(double), typeof(RibbonProperties),
- new FrameworkPropertyMetadata(25D, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits));
+ new FrameworkPropertyMetadata(27D, FrameworkPropertyMetadataOptions.AffectsMeasure | FrameworkPropertyMetadataOptions.Inherits));
///
/// Sets TitleBarHeight for element
diff --git a/Fluent.Ribbon/Controls/Backstage.cs b/Fluent.Ribbon/Controls/Backstage.cs
index edc0a281a..2ceefd262 100644
--- a/Fluent.Ribbon/Controls/Backstage.cs
+++ b/Fluent.Ribbon/Controls/Backstage.cs
@@ -14,7 +14,7 @@ namespace Fluent
using System.Windows.Media;
using System.Windows.Threading;
using System.Threading;
- using System.Threading.Tasks;
+ using System.Threading.Tasks;
using Fluent.Extensions;
using Fluent.Internal;
@@ -65,7 +65,7 @@ public Duration HideAnimationDuration
/// Using a DependencyProperty as the backing store for HideAnimationDuration.
/// This enables animation, styling, binding, etc...
///
- public static readonly DependencyProperty HideAnimationDurationProperty =
+ public static readonly DependencyProperty HideAnimationDurationProperty =
DependencyProperty.Register(nameof(HideAnimationDuration), typeof(Duration), typeof(Backstage), new PropertyMetadata(null));
///
@@ -96,7 +96,7 @@ public bool IsOpenAnimationEnabled
/// Using a DependencyProperty as the backing store for HideContextTabsOnOpen.
/// This enables animation, styling, binding, etc...
///
- public static readonly DependencyProperty HideContextTabsOnOpenProperty =
+ public static readonly DependencyProperty HideContextTabsOnOpenProperty =
DependencyProperty.Register(nameof(HideContextTabsOnOpen), typeof(bool), typeof(Backstage), new PropertyMetadata(false));
///
@@ -112,7 +112,7 @@ public bool CloseOnEsc
/// Using a DependencyProperty as the backing store for CloseOnEsc.
/// This enables animation, styling, binding, etc...
///
- public static readonly DependencyProperty CloseOnEscProperty =
+ public static readonly DependencyProperty CloseOnEscProperty =
DependencyProperty.Register(nameof(CloseOnEsc), typeof(bool), typeof(Backstage), new PropertyMetadata(true));
private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
@@ -373,77 +373,34 @@ private void CreateAndAttachBackstageAdorner()
return;
}
- FrameworkElement topLevelElement = null;
+ FrameworkElement elementToAdorn;
if (DesignerProperties.GetIsInDesignMode(this))
{
// TODO: in design mode it is required to use design time adorner
- topLevelElement = (FrameworkElement)VisualTreeHelper.GetParent(this);
+ elementToAdorn = (FrameworkElement)VisualTreeHelper.GetParent(this);
}
else
{
- var mainWindow = Window.GetWindow(this);
- if (mainWindow == null)
- {
- return;
- }
-
- var content = mainWindow.Content;
-
- var fe = content as FrameworkElement; // Content may be an arbitrary .NET object when set using a databinding and using data templates.
-
- if (fe != null)
- {
- topLevelElement = fe;
- }
- else
- {
- // If Content is not a FrameworkElement we try to find the ContentPresenter
- // containing the template to display the content.
- var contentPresenter = UIHelper.FindVisualChild(mainWindow);
-
- if (contentPresenter != null
- && ReferenceEquals(contentPresenter.Content, content))
- {
- // set the root element of the template as the top level element.
- topLevelElement = (FrameworkElement)VisualTreeHelper.GetChild(contentPresenter, 0);
- }
- }
+ elementToAdorn = UIHelper.GetParent(this);
}
- if (topLevelElement == null)
+ if (elementToAdorn == null)
{
return;
- }
-
- var layer = this.GetAdornerLayer();
-
- 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;
+ this.adorner = new BackstageAdorner(elementToAdorn, this);
+ layer.Add(this.adorner);
+
+ layer.CommandBindings.Add(new CommandBinding(RibbonCommands.OpenBackstage, HandleOpenBackstageCommandExecuted));
}
private static void HandleOpenBackstageCommandExecuted(object sender, ExecutedRoutedEventArgs args)
@@ -629,7 +586,7 @@ private void CollapseWindowsFormsHosts(DependencyObject parent)
if (frameworkElement != null)
{
- if (parent is HwndHost
+ if (parent is HwndHost
&& frameworkElement.Visibility != Visibility.Collapsed)
{
this.collapsedElements.Add(frameworkElement, frameworkElement.Visibility);
@@ -656,7 +613,7 @@ protected override void OnKeyDown(KeyEventArgs e)
return;
}
- if (e.Key == Key.Enter
+ if (e.Key == Key.Enter
|| e.Key == Key.Space)
{
if (this.IsFocused)
@@ -677,6 +634,7 @@ private void HandleWindowKeyDown(object sender, KeyEventArgs e)
{
return;
}
+
// only handle ESC when the backstage is open
e.Handled = this.IsOpen;
diff --git a/Fluent.Ribbon/Controls/BackstageTabControl.cs b/Fluent.Ribbon/Controls/BackstageTabControl.cs
index 1b6e2259b..18aa387e7 100644
--- a/Fluent.Ribbon/Controls/BackstageTabControl.cs
+++ b/Fluent.Ribbon/Controls/BackstageTabControl.cs
@@ -10,6 +10,8 @@
namespace Fluent
{
+ using Fluent.Internal;
+
///
/// Represents Backstage tab control.
///
@@ -189,6 +191,23 @@ public Brush ItemsPanelBackground
#endregion
+ ///
+ /// Gets or sets the
+ ///
+ [Browsable(false)]
+ [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
+ public Backstage ParentBackstage
+ {
+ get { return (Backstage)this.GetValue(ParentBackstageProperty); }
+ set { this.SetValue(ParentBackstageProperty, value); }
+ }
+
+ ///
+ /// for
+ ///
+ public static readonly DependencyProperty ParentBackstageProperty =
+ DependencyProperty.Register(nameof(ParentBackstage), typeof(Backstage), typeof(BackstageTabControl), new PropertyMetadata(null));
+
#endregion
#region Constructors
@@ -200,11 +219,11 @@ public Brush ItemsPanelBackground
static BackstageTabControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(BackstageTabControl), new FrameworkPropertyMetadata(typeof(BackstageTabControl)));
- StyleProperty.OverrideMetadata(typeof(BackstageTabControl), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle)));
+ StyleProperty.OverrideMetadata(typeof(BackstageTabControl), new FrameworkPropertyMetadata(null, OnCoerceStyle));
}
// Coerce object style
- static object OnCoerceStyle(DependencyObject d, object basevalue)
+ private static object OnCoerceStyle(DependencyObject d, object basevalue)
{
if (basevalue == null)
{
@@ -227,6 +246,19 @@ public BackstageTabControl()
HasDropShadow = false
};
this.ContextMenu.Opened += delegate { this.ContextMenu.IsOpen = false; };
+
+ this.Loaded += this.HandleLoaded;
+ this.Unloaded += this.HandleUnloaded;
+ }
+
+ private void HandleLoaded(object sender, RoutedEventArgs e)
+ {
+ this.ParentBackstage = UIHelper.GetParent(this);
+ }
+
+ private void HandleUnloaded(object sender, RoutedEventArgs e)
+ {
+ this.ParentBackstage = null;
}
#endregion
diff --git a/Fluent.Ribbon/Controls/CheckBox.cs b/Fluent.Ribbon/Controls/CheckBox.cs
index 093cd3537..6d487bb9e 100644
--- a/Fluent.Ribbon/Controls/CheckBox.cs
+++ b/Fluent.Ribbon/Controls/CheckBox.cs
@@ -123,9 +123,9 @@ private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedE
///
/// Gets or sets button large icon
///
- public ImageSource LargeIcon
+ public object LargeIcon
{
- get { return (ImageSource)this.GetValue(LargeIconProperty); }
+ get { return this.GetValue(LargeIconProperty); }
set { this.SetValue(LargeIconProperty, value); }
}
@@ -133,9 +133,7 @@ public ImageSource LargeIcon
/// Using a DependencyProperty as the backing store for SmallIcon.
/// This enables animation, styling, binding, etc...
///
- public static readonly DependencyProperty LargeIconProperty =
- DependencyProperty.Register("LargeIcon", typeof(ImageSource),
- typeof(CheckBox), new UIPropertyMetadata(null));
+ public static readonly DependencyProperty LargeIconProperty = DependencyProperty.Register("LargeIcon", typeof(object), typeof(CheckBox), new UIPropertyMetadata(null));
#endregion
diff --git a/Fluent.Ribbon/Controls/ComboBox.cs b/Fluent.Ribbon/Controls/ComboBox.cs
index 61cc796dc..d25adfaa3 100644
--- a/Fluent.Ribbon/Controls/ComboBox.cs
+++ b/Fluent.Ribbon/Controls/ComboBox.cs
@@ -1,971 +1,971 @@
namespace Fluent
{
- using System;
- using System.Diagnostics;
- using System.Diagnostics.CodeAnalysis;
- using System.Threading;
- using System.Windows;
- using System.Windows.Controls;
- using System.Windows.Controls.Primitives;
- using System.Windows.Data;
- using System.Windows.Input;
- using System.Windows.Media;
- using System.Windows.Media.Imaging;
- using System.Windows.Threading;
- using Fluent.Internal;
+ using System;
+ using System.Diagnostics;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Threading;
+ using System.Windows;
+ using System.Windows.Controls;
+ using System.Windows.Controls.Primitives;
+ using System.Windows.Data;
+ using System.Windows.Input;
+ using System.Windows.Media;
+ using System.Windows.Media.Imaging;
+ using System.Windows.Threading;
+ using Fluent.Internal;
///
/// Represents custom Fluent UI ComboBox
///
[TemplatePart(Name = "PART_ResizeBothThumb", Type = typeof(Thumb))]
- [TemplatePart(Name = "PART_ResizeVerticalThumb", Type = typeof(Thumb))]
- public class ComboBox : System.Windows.Controls.ComboBox, IQuickAccessItemProvider, IRibbonControl, IDropDownControl
- {
- #region Fields
+ [TemplatePart(Name = "PART_ResizeVerticalThumb", Type = typeof(Thumb))]
+ public class ComboBox : System.Windows.Controls.ComboBox, IQuickAccessItemProvider, IRibbonControl, IDropDownControl
+ {
+ #region Fields
- // Thumb to resize in both directions
- private Thumb resizeBothThumb;
- // Thumb to resize vertical
- private Thumb resizeVerticalThumb;
+ // Thumb to resize in both directions
+ private Thumb resizeBothThumb;
+ // Thumb to resize vertical
+ private Thumb resizeVerticalThumb;
- private IInputElement focusedElement;
+ private IInputElement focusedElement;
- private Panel menuPanel;
+ private Panel menuPanel;
- private Border dropDownBorder;
- private Border contentBorder;
+ private Border dropDownBorder;
+ private Border contentBorder;
- private ContentPresenter contentSite;
+ private ContentPresenter contentSite;
- // Freezed image (created during snapping)
- private Image snappedImage;
+ // Freezed image (created during snapping)
+ private Image snappedImage;
- // Is visual currently snapped
- private bool isSnapped;
+ // Is visual currently snapped
+ private bool isSnapped;
- private GalleryPanel galleryPanel;
+ private GalleryPanel galleryPanel;
- private ScrollViewer scrollViewer;
+ private ScrollViewer scrollViewer;
- private bool canSizeY;
+ private bool canSizeY;
- #endregion
+ #endregion
- #region Properties
+ #region Properties
- #region Size
+ #region Size
- ///
- /// Gets or sets Size for the element.
- ///
- public RibbonControlSize Size
- {
- get { return (RibbonControlSize)this.GetValue(SizeProperty); }
- set { this.SetValue(SizeProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for Size.
- /// This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(ComboBox));
-
- #endregion
-
- #region SizeDefinition
-
- ///
- /// Gets or sets SizeDefinition for element.
- ///
- public RibbonControlSizeDefinition SizeDefinition
- {
- get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); }
- set { this.SetValue(SizeDefinitionProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for SizeDefinition.
- /// This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(ComboBox));
-
- #endregion
-
- #region KeyTip
-
- ///
- /// Gets or sets KeyTip for element.
- ///
- public string KeyTip
- {
- get { return (string)this.GetValue(KeyTipProperty); }
- set { this.SetValue(KeyTipProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for Keys.
- /// This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(ComboBox));
-
- #endregion
-
- ///
- /// Gets drop down popup
- ///
- public Popup DropDownPopup { get; private set; }
-
- ///
- /// Gets a value indicating whether context menu is opened
- ///
- public bool IsContextMenuOpened { get; set; }
-
- #region Header
-
- ///
- /// Gets or sets element Text
- ///
- public object Header
- {
- get { return (string)this.GetValue(HeaderProperty); }
- set { this.SetValue(HeaderProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for Header.
- /// This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(ComboBox));
-
- #endregion
-
- #region Icon
-
- ///
- /// Gets or sets Icon for the element
- ///
- public object Icon
- {
- get { return (ImageSource)this.GetValue(IconProperty); }
- set { this.SetValue(IconProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(ComboBox), new UIPropertyMetadata(null, OnIconChanged));
-
- private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var element = d as ComboBox;
- var oldElement = e.OldValue as FrameworkElement;
- if (oldElement != null) element.RemoveLogicalChild(oldElement);
- var newElement = e.NewValue as FrameworkElement;
- if (newElement != null) element.AddLogicalChild(newElement);
- }
-
- #endregion
-
- #region Menu
-
- ///
- /// Gets or sets menu to show in combo box bottom
- ///
- public RibbonMenu Menu
- {
- get { return (RibbonMenu)this.GetValue(MenuProperty); }
- set { this.SetValue(MenuProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for Menu. This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty MenuProperty =
- DependencyProperty.Register("Menu", typeof(RibbonMenu), typeof(ComboBox), new UIPropertyMetadata(null));
-
- #endregion
-
- #region InputWidth
-
- ///
- /// Gets or sets width of the value input part of combobox
- ///
- public double InputWidth
- {
- get { return (double)this.GetValue(InputWidthProperty); }
- set { this.SetValue(InputWidthProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for InputWidth. This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty InputWidthProperty =
- DependencyProperty.Register("InputWidth", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN));
-
- #endregion
-
- #region ItemHeight
-
- ///
- /// Gets or sets items height
- ///
- public double ItemHeight
- {
- get { return (double)this.GetValue(ItemHeightProperty); }
- set { this.SetValue(ItemHeightProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for ItemHeight. This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty ItemHeightProperty =
- DependencyProperty.Register("ItemHeight", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN));
-
- #endregion
-
- #region GroupBy
-
- ///
- /// Gets or sets name of property which
- /// will use to group items in the ComboBox.
- ///
- public string GroupBy
- {
- get { return (string)this.GetValue(GroupByProperty); }
- set { this.SetValue(GroupByProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for GroupBy.
- /// This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty GroupByProperty =
- DependencyProperty.Register("GroupBy", typeof(string),
- typeof(ComboBox), new UIPropertyMetadata(null));
-
- #endregion
-
- #region ResizeMode
-
- ///
- /// Gets or sets context menu resize mode
- ///
- public ContextMenuResizeMode ResizeMode
- {
- get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); }
- set { this.SetValue(ResizeModeProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for ResizeMode. This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty ResizeModeProperty =
- DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), typeof(ComboBox), new UIPropertyMetadata(ContextMenuResizeMode.None));
-
- #endregion
-
- #region Snapping
-
- ///
- /// Snaps / Unsnaps the Visual
- /// (remove visuals and substitute with freezed image)
- ///
- private bool IsSnapped
- {
- get { return this.isSnapped; }
- set
- {
- if (value == this.isSnapped) return;
- if (this.snappedImage == null) return;
- if ((value) && (((int)this.contentSite.ActualWidth > 0) && ((int)this.contentSite.ActualHeight > 0)))
- {
- // Render the freezed image
- RenderOptions.SetBitmapScalingMode(this.snappedImage, BitmapScalingMode.NearestNeighbor);
- var renderTargetBitmap = new RenderTargetBitmap((int)this.contentSite.ActualWidth + (int)this.contentSite.Margin.Left + (int)this.contentSite.Margin.Right,
- (int)this.contentSite.ActualHeight + (int)this.contentSite.Margin.Top + (int)this.contentSite.Margin.Bottom, 96, 96,
- PixelFormats.Pbgra32);
- renderTargetBitmap.Render(this.contentSite);
- this.snappedImage.Source = renderTargetBitmap;
- this.snappedImage.FlowDirection = this.FlowDirection;
- /*snappedImage.Width = contentSite.ActualWidth;
+ ///
+ /// Gets or sets Size for the element.
+ ///
+ public RibbonControlSize Size
+ {
+ get { return (RibbonControlSize)this.GetValue(SizeProperty); }
+ set { this.SetValue(SizeProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for Size.
+ /// This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty SizeProperty = RibbonProperties.SizeProperty.AddOwner(typeof(ComboBox));
+
+ #endregion
+
+ #region SizeDefinition
+
+ ///
+ /// Gets or sets SizeDefinition for element.
+ ///
+ public RibbonControlSizeDefinition SizeDefinition
+ {
+ get { return (RibbonControlSizeDefinition)this.GetValue(SizeDefinitionProperty); }
+ set { this.SetValue(SizeDefinitionProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for SizeDefinition.
+ /// This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty SizeDefinitionProperty = RibbonProperties.SizeDefinitionProperty.AddOwner(typeof(ComboBox));
+
+ #endregion
+
+ #region KeyTip
+
+ ///
+ /// Gets or sets KeyTip for element.
+ ///
+ public string KeyTip
+ {
+ get { return (string)this.GetValue(KeyTipProperty); }
+ set { this.SetValue(KeyTipProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for Keys.
+ /// This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty KeyTipProperty = Fluent.KeyTip.KeysProperty.AddOwner(typeof(ComboBox));
+
+ #endregion
+
+ ///
+ /// Gets drop down popup
+ ///
+ public Popup DropDownPopup { get; private set; }
+
+ ///
+ /// Gets a value indicating whether context menu is opened
+ ///
+ public bool IsContextMenuOpened { get; set; }
+
+ #region Header
+
+ ///
+ /// Gets or sets element Text
+ ///
+ public object Header
+ {
+ get { return (string)this.GetValue(HeaderProperty); }
+ set { this.SetValue(HeaderProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for Header.
+ /// This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty HeaderProperty = RibbonControl.HeaderProperty.AddOwner(typeof(ComboBox));
+
+ #endregion
+
+ #region Icon
+
+ ///
+ /// Gets or sets Icon for the element
+ ///
+ public object Icon
+ {
+ get { return this.GetValue(IconProperty); }
+ set { this.SetValue(IconProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(ComboBox), new UIPropertyMetadata(null, OnIconChanged));
+
+ private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var element = d as ComboBox;
+ var oldElement = e.OldValue as FrameworkElement;
+ if (oldElement != null) element.RemoveLogicalChild(oldElement);
+ var newElement = e.NewValue as FrameworkElement;
+ if (newElement != null) element.AddLogicalChild(newElement);
+ }
+
+ #endregion
+
+ #region Menu
+
+ ///
+ /// Gets or sets menu to show in combo box bottom
+ ///
+ public RibbonMenu Menu
+ {
+ get { return (RibbonMenu)this.GetValue(MenuProperty); }
+ set { this.SetValue(MenuProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for Menu. This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty MenuProperty =
+ DependencyProperty.Register("Menu", typeof(RibbonMenu), typeof(ComboBox), new UIPropertyMetadata(null));
+
+ #endregion
+
+ #region InputWidth
+
+ ///
+ /// Gets or sets width of the value input part of combobox
+ ///
+ public double InputWidth
+ {
+ get { return (double)this.GetValue(InputWidthProperty); }
+ set { this.SetValue(InputWidthProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for InputWidth. This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty InputWidthProperty =
+ DependencyProperty.Register("InputWidth", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN));
+
+ #endregion
+
+ #region ItemHeight
+
+ ///
+ /// Gets or sets items height
+ ///
+ public double ItemHeight
+ {
+ get { return (double)this.GetValue(ItemHeightProperty); }
+ set { this.SetValue(ItemHeightProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for ItemHeight. This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty ItemHeightProperty =
+ DependencyProperty.Register("ItemHeight", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN));
+
+ #endregion
+
+ #region GroupBy
+
+ ///
+ /// Gets or sets name of property which
+ /// will use to group items in the ComboBox.
+ ///
+ public string GroupBy
+ {
+ get { return (string)this.GetValue(GroupByProperty); }
+ set { this.SetValue(GroupByProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for GroupBy.
+ /// This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty GroupByProperty =
+ DependencyProperty.Register("GroupBy", typeof(string),
+ typeof(ComboBox), new UIPropertyMetadata(null));
+
+ #endregion
+
+ #region ResizeMode
+
+ ///
+ /// Gets or sets context menu resize mode
+ ///
+ public ContextMenuResizeMode ResizeMode
+ {
+ get { return (ContextMenuResizeMode)this.GetValue(ResizeModeProperty); }
+ set { this.SetValue(ResizeModeProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for ResizeMode. This enables animation, styling, binding, etc...
+ ///
+ public static readonly DependencyProperty ResizeModeProperty =
+ DependencyProperty.Register("ResizeMode", typeof(ContextMenuResizeMode), typeof(ComboBox), new UIPropertyMetadata(ContextMenuResizeMode.None));
+
+ #endregion
+
+ #region Snapping
+
+ ///
+ /// Snaps / Unsnaps the Visual
+ /// (remove visuals and substitute with freezed image)
+ ///
+ private bool IsSnapped
+ {
+ get { return this.isSnapped; }
+ set
+ {
+ if (value == this.isSnapped) return;
+ if (this.snappedImage == null) return;
+ if ((value) && (((int)this.contentSite.ActualWidth > 0) && ((int)this.contentSite.ActualHeight > 0)))
+ {
+ // Render the freezed image
+ RenderOptions.SetBitmapScalingMode(this.snappedImage, BitmapScalingMode.NearestNeighbor);
+ var renderTargetBitmap = new RenderTargetBitmap((int)this.contentSite.ActualWidth + (int)this.contentSite.Margin.Left + (int)this.contentSite.Margin.Right,
+ (int)this.contentSite.ActualHeight + (int)this.contentSite.Margin.Top + (int)this.contentSite.Margin.Bottom, 96, 96,
+ PixelFormats.Pbgra32);
+ renderTargetBitmap.Render(this.contentSite);
+ this.snappedImage.Source = renderTargetBitmap;
+ this.snappedImage.FlowDirection = this.FlowDirection;
+ /*snappedImage.Width = contentSite.ActualWidth;
snappedImage.Height = contentSite.ActualHeight;*/
- this.snappedImage.Visibility = Visibility.Visible;
- this.contentSite.Visibility = Visibility.Hidden;
- this.isSnapped = value;
- }
- else
- {
- this.snappedImage.Visibility = Visibility.Collapsed;
- this.contentSite.Visibility = Visibility.Visible;
- this.isSnapped = value;
- }
-
- this.InvalidateVisual();
- }
- }
-
- #endregion
-
- #region DropDownHeight
-
- ///
- /// Gets or sets initial dropdown height
- ///
- public double DropDownHeight
- {
- get { return (double)this.GetValue(DropDownHeightProperty); }
- set { this.SetValue(DropDownHeightProperty, value); }
- }
-
- ///
- /// /Using a DependencyProperty as the backing store for DropDownHeight. This enables animation, styling, binding,
- /// etc...
- ///
- public static readonly DependencyProperty DropDownHeightProperty =
- DependencyProperty.Register("InitialDropDownHeight", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN));
-
- #endregion
-
- #region ShowPopupOnTop
-
- ///
- /// Gets a value indicating whether popup is shown on top;
- ///
- public bool ShowPopupOnTop
- {
- get { return (bool)this.GetValue(ShowPopupOnTopProperty); }
- private set { this.SetValue(ShowPopupOnTopPropertyKey, value); }
- }
-
- //
- private static readonly DependencyPropertyKey ShowPopupOnTopPropertyKey = DependencyProperty.RegisterReadOnly("ShowPopupOnTop", typeof(bool), typeof(ComboBox), new UIPropertyMetadata(false));
-
- ///
- /// Using a DependencyProperty as the backing store for ShowPopupOnTop. This enables animation, styling, binding,
- /// etc...
- ///
- public static readonly DependencyProperty ShowPopupOnTopProperty = ShowPopupOnTopPropertyKey.DependencyProperty;
-
- #endregion
-
- #endregion
-
- #region Constructors
-
- ///
- /// Static constructor
- ///
- [SuppressMessage("Microsoft.Performance", "CA1810")]
- static ComboBox()
- {
- var type = typeof(ComboBox);
- ToolTipService.Attach(type);
- PopupService.Attach(type);
- ContextMenuService.Attach(type);
- DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type));
- SelectedItemProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(OnSelectionItemChanged, CoerceSelectedItem));
- }
-
- private static void OnSelectionItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var combo = d as ComboBox;
- if (!combo.isQuickAccessOpened && !combo.isQuickAccessFocused && (combo.quickAccessCombo != null)) combo.UpdateQuickAccessCombo();
- }
-
- private static object CoerceSelectedItem(DependencyObject d, object basevalue)
- {
- var combo = d as ComboBox;
- if (combo.isQuickAccessOpened || combo.isQuickAccessFocused) return combo.selectedItem;
- return basevalue;
- }
-
- ///
- /// Default Constructor
- ///
- public ComboBox()
- {
- ContextMenuService.Coerce(this);
- }
-
- #endregion
-
- #region QuickAccess
-
- ///
- /// Gets control which represents shortcut item.
- /// This item MUST be syncronized with the original
- /// and send command to original one control.
- ///
- /// Control which represents shortcut item
- public virtual FrameworkElement CreateQuickAccessItem()
- {
- var combo = new ComboBox();
- RibbonControl.BindQuickAccessItem(this, combo);
- RibbonControl.Bind(this, combo, "GroupBy", GroupByProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "ActualWidth", WidthProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "InputWidth", InputWidthProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "ItemHeight", ItemHeightProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "IsEditable", IsEditableProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "IsReadOnly", IsReadOnlyProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "ResizeMode", ResizeModeProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "Text", TextProperty, BindingMode.TwoWay);
-
- RibbonControl.Bind(this, combo, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "SelectedValuePath", SelectedValuePathProperty, BindingMode.OneWay);
- RibbonControl.Bind(this, combo, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay);
- combo.DropDownOpened += this.OnQuickAccessOpened;
- if (this.IsEditable) combo.GotFocus += this.OnQuickAccessTextBoxGetFocus;
- this.quickAccessCombo = combo;
- this.UpdateQuickAccessCombo();
- return combo;
- }
-
- private void OnQuickAccessTextBoxGetFocus(object sender, RoutedEventArgs e)
- {
- this.isQuickAccessFocused = true;
- if (!this.isQuickAccessOpened) this.Freeze();
- this.quickAccessCombo.LostFocus += this.OnQuickAccessTextBoxLostFocus;
- }
-
- private void OnQuickAccessTextBoxLostFocus(object sender, RoutedEventArgs e)
- {
- this.quickAccessCombo.LostFocus -= this.OnQuickAccessTextBoxLostFocus;
- if (!this.isQuickAccessOpened) this.Unfreeze();
- this.isQuickAccessFocused = false;
- }
-
- private bool isQuickAccessFocused;
- private bool isQuickAccessOpened;
- private object selectedItem;
- private ComboBox quickAccessCombo;
-
- private void OnQuickAccessOpened(object sender, EventArgs e)
- {
- this.isQuickAccessOpened = true;
- this.quickAccessCombo.DropDownClosed += this.OnQuickAccessMenuClosed;
- this.quickAccessCombo.UpdateLayout();
- if (!this.isQuickAccessFocused)
- this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, ((ThreadStart)(() =>
- {
- this.Freeze();
- this.Dispatcher.BeginInvoke(DispatcherPriority.Input, ((ThreadStart)(() => { if (this.quickAccessCombo.SelectedItem != null) (this.quickAccessCombo.ItemContainerGenerator.ContainerFromItem(this.quickAccessCombo.SelectedItem) as ComboBoxItem).BringIntoView(); }
- )));
- }
- )));
- }
-
- private void OnQuickAccessMenuClosed(object sender, EventArgs e)
- {
- this.quickAccessCombo.DropDownClosed -= this.OnQuickAccessMenuClosed;
- if (!this.isQuickAccessFocused) this.Unfreeze();
- this.isQuickAccessOpened = false;
- }
-
- private void Freeze()
- {
- this.IsSnapped = true;
- this.selectedItem = this.SelectedItem;
+ this.snappedImage.Visibility = Visibility.Visible;
+ this.contentSite.Visibility = Visibility.Hidden;
+ this.isSnapped = value;
+ }
+ else
+ {
+ this.snappedImage.Visibility = Visibility.Collapsed;
+ this.contentSite.Visibility = Visibility.Visible;
+ this.isSnapped = value;
+ }
+
+ this.InvalidateVisual();
+ }
+ }
+
+ #endregion
+
+ #region DropDownHeight
+
+ ///
+ /// Gets or sets initial dropdown height
+ ///
+ public double DropDownHeight
+ {
+ get { return (double)this.GetValue(DropDownHeightProperty); }
+ set { this.SetValue(DropDownHeightProperty, value); }
+ }
+
+ ///
+ /// /Using a DependencyProperty as the backing store for DropDownHeight. This enables animation, styling, binding,
+ /// etc...
+ ///
+ public static readonly DependencyProperty DropDownHeightProperty =
+ DependencyProperty.Register("InitialDropDownHeight", typeof(double), typeof(ComboBox), new UIPropertyMetadata(double.NaN));
+
+ #endregion
+
+ #region ShowPopupOnTop
+
+ ///
+ /// Gets a value indicating whether popup is shown on top;
+ ///
+ public bool ShowPopupOnTop
+ {
+ get { return (bool)this.GetValue(ShowPopupOnTopProperty); }
+ private set { this.SetValue(ShowPopupOnTopPropertyKey, value); }
+ }
+
+ //
+ private static readonly DependencyPropertyKey ShowPopupOnTopPropertyKey = DependencyProperty.RegisterReadOnly("ShowPopupOnTop", typeof(bool), typeof(ComboBox), new UIPropertyMetadata(false));
+
+ ///
+ /// Using a DependencyProperty as the backing store for ShowPopupOnTop. This enables animation, styling, binding,
+ /// etc...
+ ///
+ public static readonly DependencyProperty ShowPopupOnTopProperty = ShowPopupOnTopPropertyKey.DependencyProperty;
+
+ #endregion
+
+ #endregion
+
+ #region Constructors
+
+ ///
+ /// Static constructor
+ ///
+ [SuppressMessage("Microsoft.Performance", "CA1810")]
+ static ComboBox()
+ {
+ var type = typeof(ComboBox);
+ ToolTipService.Attach(type);
+ PopupService.Attach(type);
+ ContextMenuService.Attach(type);
+ DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type));
+ SelectedItemProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(OnSelectionItemChanged, CoerceSelectedItem));
+ }
+
+ private static void OnSelectionItemChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var combo = d as ComboBox;
+ if (!combo.isQuickAccessOpened && !combo.isQuickAccessFocused && (combo.quickAccessCombo != null)) combo.UpdateQuickAccessCombo();
+ }
+
+ private static object CoerceSelectedItem(DependencyObject d, object basevalue)
+ {
+ var combo = d as ComboBox;
+ if (combo.isQuickAccessOpened || combo.isQuickAccessFocused) return combo.selectedItem;
+ return basevalue;
+ }
+
+ ///
+ /// Default Constructor
+ ///
+ public ComboBox()
+ {
+ ContextMenuService.Coerce(this);
+ }
+
+ #endregion
+
+ #region QuickAccess
+
+ ///
+ /// Gets control which represents shortcut item.
+ /// This item MUST be syncronized with the original
+ /// and send command to original one control.
+ ///
+ /// Control which represents shortcut item
+ public virtual FrameworkElement CreateQuickAccessItem()
+ {
+ var combo = new ComboBox();
+ RibbonControl.BindQuickAccessItem(this, combo);
+ RibbonControl.Bind(this, combo, "GroupBy", GroupByProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "ActualWidth", WidthProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "InputWidth", InputWidthProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "ItemHeight", ItemHeightProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "IsEditable", IsEditableProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "IsReadOnly", IsReadOnlyProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "ResizeMode", ResizeModeProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "Text", TextProperty, BindingMode.TwoWay);
+
+ RibbonControl.Bind(this, combo, "DisplayMemberPath", DisplayMemberPathProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "GroupStyleSelector", GroupStyleSelectorProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "ItemContainerStyle", ItemContainerStyleProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "ItemsPanel", ItemsPanelProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "ItemStringFormat", ItemStringFormatProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "ItemTemplate", ItemTemplateProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "SelectedValuePath", SelectedValuePathProperty, BindingMode.OneWay);
+ RibbonControl.Bind(this, combo, "MaxDropDownHeight", MaxDropDownHeightProperty, BindingMode.OneWay);
+ combo.DropDownOpened += this.OnQuickAccessOpened;
+ if (this.IsEditable) combo.GotFocus += this.OnQuickAccessTextBoxGetFocus;
+ this.quickAccessCombo = combo;
+ this.UpdateQuickAccessCombo();
+ return combo;
+ }
+
+ private void OnQuickAccessTextBoxGetFocus(object sender, RoutedEventArgs e)
+ {
+ this.isQuickAccessFocused = true;
+ if (!this.isQuickAccessOpened) this.Freeze();
+ this.quickAccessCombo.LostFocus += this.OnQuickAccessTextBoxLostFocus;
+ }
+
+ private void OnQuickAccessTextBoxLostFocus(object sender, RoutedEventArgs e)
+ {
+ this.quickAccessCombo.LostFocus -= this.OnQuickAccessTextBoxLostFocus;
+ if (!this.isQuickAccessOpened) this.Unfreeze();
+ this.isQuickAccessFocused = false;
+ }
+
+ private bool isQuickAccessFocused;
+ private bool isQuickAccessOpened;
+ private object selectedItem;
+ private ComboBox quickAccessCombo;
+
+ private void OnQuickAccessOpened(object sender, EventArgs e)
+ {
+ this.isQuickAccessOpened = true;
+ this.quickAccessCombo.DropDownClosed += this.OnQuickAccessMenuClosed;
+ this.quickAccessCombo.UpdateLayout();
+ if (!this.isQuickAccessFocused)
+ this.Dispatcher.BeginInvoke(DispatcherPriority.Normal, ((ThreadStart)(() =>
+ {
+ this.Freeze();
+ this.Dispatcher.BeginInvoke(DispatcherPriority.Input, ((ThreadStart)(() => { if (this.quickAccessCombo.SelectedItem != null) (this.quickAccessCombo.ItemContainerGenerator.ContainerFromItem(this.quickAccessCombo.SelectedItem) as ComboBoxItem).BringIntoView(); }
+ )));
+ }
+ )));
+ }
+
+ private void OnQuickAccessMenuClosed(object sender, EventArgs e)
+ {
+ this.quickAccessCombo.DropDownClosed -= this.OnQuickAccessMenuClosed;
+ if (!this.isQuickAccessFocused) this.Unfreeze();
+ this.isQuickAccessOpened = false;
+ }
+
+ private void Freeze()
+ {
+ this.IsSnapped = true;
+ this.selectedItem = this.SelectedItem;
ItemsControlHelper.MoveItemsToDifferentControl(this, this.quickAccessCombo);
this.SelectedItem = null;
- this.quickAccessCombo.SelectedItem = this.selectedItem;
- this.quickAccessCombo.Menu = this.Menu;
- this.Menu = null;
- this.quickAccessCombo.IsSnapped = false;
- }
-
- private void Unfreeze()
- {
- var text = this.quickAccessCombo.Text;
- this.selectedItem = this.quickAccessCombo.SelectedItem;
- this.quickAccessCombo.IsSnapped = true;
+ this.quickAccessCombo.SelectedItem = this.selectedItem;
+ this.quickAccessCombo.Menu = this.Menu;
+ this.Menu = null;
+ this.quickAccessCombo.IsSnapped = false;
+ }
+
+ private void Unfreeze()
+ {
+ var text = this.quickAccessCombo.Text;
+ this.selectedItem = this.quickAccessCombo.SelectedItem;
+ this.quickAccessCombo.IsSnapped = true;
ItemsControlHelper.MoveItemsToDifferentControl(this.quickAccessCombo, this);
- this.quickAccessCombo.SelectedItem = null;
- this.SelectedItem = this.selectedItem;
- this.Menu = this.quickAccessCombo.Menu;
- this.quickAccessCombo.Menu = null;
- this.IsSnapped = false;
- this.Text = text;
- this.UpdateLayout();
- }
-
- private void UpdateQuickAccessCombo()
- {
- if (this.IsLoaded == false)
- {
- this.Loaded += this.OnFirstLoaded;
- }
-
- if (this.IsEditable == false)
- {
- this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (ThreadStart)(() =>
- {
- this.quickAccessCombo.IsSnapped = true;
- this.IsSnapped = true;
- if (this.snappedImage != null &&
- this.quickAccessCombo.snappedImage != null)
- {
- this.quickAccessCombo.snappedImage.Source = this.snappedImage.Source;
- this.quickAccessCombo.snappedImage.Visibility = Visibility.Visible;
- if (this.quickAccessCombo.IsSnapped == false)
- {
- this.quickAccessCombo.isSnapped = true;
- }
- }
- this.IsSnapped = false;
- }));
- }
- }
-
- private void OnFirstLoaded(object sender, RoutedEventArgs e)
- {
- this.Loaded -= this.OnFirstLoaded;
- this.UpdateQuickAccessCombo();
- }
-
- ///
- /// Gets or sets whether control can be added to quick access toolbar
- ///
- public bool CanAddToQuickAccessToolBar
- {
- get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); }
- set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling,
- /// binding, etc...
- ///
- public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(ComboBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged));
-
- #endregion
-
- #region Overrides
-
- ///
- /// When overridden in a derived class, is invoked whenever application code or internal processes call
- /// .
- ///
- public override void OnApplyTemplate()
- {
- this.DropDownPopup = this.GetTemplateChild("PART_Popup") as Popup;
-
- if (this.resizeVerticalThumb != null)
- {
- this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta;
- }
- this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb;
- if (this.resizeVerticalThumb != null)
- {
- this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta;
- }
-
- if (this.resizeBothThumb != null)
- {
- this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta;
- }
- this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb;
- if (this.resizeBothThumb != null)
- {
- this.resizeBothThumb.DragDelta += this.OnResizeBothDelta;
- }
-
- this.menuPanel = this.GetTemplateChild("PART_MenuPanel") as Panel;
-
- this.snappedImage = this.GetTemplateChild("PART_SelectedImage") as Image;
- this.contentSite = this.GetTemplateChild("PART_ContentSite") as ContentPresenter;
-
- if (this.contentBorder != null) this.contentBorder.PreviewMouseDown -= this.OnContentBorderPreviewMouseDown;
- this.contentBorder = this.GetTemplateChild("PART_ContentBorder") as Border;
- if (this.contentBorder != null) this.contentBorder.PreviewMouseDown += this.OnContentBorderPreviewMouseDown;
-
- this.galleryPanel = this.GetTemplateChild("PART_GalleryPanel") as GalleryPanel;
- this.scrollViewer = this.GetTemplateChild("PART_ScrollViewer") as ScrollViewer;
-
- this.dropDownBorder = this.GetTemplateChild("PART_DropDownBorder") as Border;
-
- base.OnApplyTemplate();
- }
-
- ///
- /// Reports when a combo box's popup opens.
- ///
- /// The event data for the event.
- protected override void OnDropDownOpened(EventArgs e)
- {
- base.OnDropDownOpened(e);
+ this.quickAccessCombo.SelectedItem = null;
+ this.SelectedItem = this.selectedItem;
+ this.Menu = this.quickAccessCombo.Menu;
+ this.quickAccessCombo.Menu = null;
+ this.IsSnapped = false;
+ this.Text = text;
+ this.UpdateLayout();
+ }
+
+ private void UpdateQuickAccessCombo()
+ {
+ if (this.IsLoaded == false)
+ {
+ this.Loaded += this.OnFirstLoaded;
+ }
+
+ if (this.IsEditable == false)
+ {
+ this.Dispatcher.BeginInvoke(DispatcherPriority.ApplicationIdle, (ThreadStart)(() =>
+ {
+ this.quickAccessCombo.IsSnapped = true;
+ this.IsSnapped = true;
+ if (this.snappedImage != null &&
+ this.quickAccessCombo.snappedImage != null)
+ {
+ this.quickAccessCombo.snappedImage.Source = this.snappedImage.Source;
+ this.quickAccessCombo.snappedImage.Visibility = Visibility.Visible;
+ if (this.quickAccessCombo.IsSnapped == false)
+ {
+ this.quickAccessCombo.isSnapped = true;
+ }
+ }
+ this.IsSnapped = false;
+ }));
+ }
+ }
+
+ private void OnFirstLoaded(object sender, RoutedEventArgs e)
+ {
+ this.Loaded -= this.OnFirstLoaded;
+ this.UpdateQuickAccessCombo();
+ }
+
+ ///
+ /// Gets or sets whether control can be added to quick access toolbar
+ ///
+ public bool CanAddToQuickAccessToolBar
+ {
+ get { return (bool)this.GetValue(CanAddToQuickAccessToolBarProperty); }
+ set { this.SetValue(CanAddToQuickAccessToolBarProperty, value); }
+ }
+
+ ///
+ /// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling,
+ /// binding, etc...
+ ///
+ public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty = RibbonControl.CanAddToQuickAccessToolBarProperty.AddOwner(typeof(ComboBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged));
+
+ #endregion
+
+ #region Overrides
+
+ ///
+ /// When overridden in a derived class, is invoked whenever application code or internal processes call
+ /// .
+ ///
+ public override void OnApplyTemplate()
+ {
+ this.DropDownPopup = this.GetTemplateChild("PART_Popup") as Popup;
+
+ if (this.resizeVerticalThumb != null)
+ {
+ this.resizeVerticalThumb.DragDelta -= this.OnResizeVerticalDelta;
+ }
+ this.resizeVerticalThumb = this.GetTemplateChild("PART_ResizeVerticalThumb") as Thumb;
+ if (this.resizeVerticalThumb != null)
+ {
+ this.resizeVerticalThumb.DragDelta += this.OnResizeVerticalDelta;
+ }
+
+ if (this.resizeBothThumb != null)
+ {
+ this.resizeBothThumb.DragDelta -= this.OnResizeBothDelta;
+ }
+ this.resizeBothThumb = this.GetTemplateChild("PART_ResizeBothThumb") as Thumb;
+ if (this.resizeBothThumb != null)
+ {
+ this.resizeBothThumb.DragDelta += this.OnResizeBothDelta;
+ }
+
+ this.menuPanel = this.GetTemplateChild("PART_MenuPanel") as Panel;
+
+ this.snappedImage = this.GetTemplateChild("PART_SelectedImage") as Image;
+ this.contentSite = this.GetTemplateChild("PART_ContentSite") as ContentPresenter;
+
+ if (this.contentBorder != null) this.contentBorder.PreviewMouseDown -= this.OnContentBorderPreviewMouseDown;
+ this.contentBorder = this.GetTemplateChild("PART_ContentBorder") as Border;
+ if (this.contentBorder != null) this.contentBorder.PreviewMouseDown += this.OnContentBorderPreviewMouseDown;
+
+ this.galleryPanel = this.GetTemplateChild("PART_GalleryPanel") as GalleryPanel;
+ this.scrollViewer = this.GetTemplateChild("PART_ScrollViewer") as ScrollViewer;
+
+ this.dropDownBorder = this.GetTemplateChild("PART_DropDownBorder") as Border;
+
+ base.OnApplyTemplate();
+ }
+
+ ///
+ /// Reports when a combo box's popup opens.
+ ///
+ /// The event data for the event.
+ protected override void OnDropDownOpened(EventArgs e)
+ {
+ base.OnDropDownOpened(e);
Mouse.Capture(this, CaptureMode.SubTree);
- if (this.SelectedItem != null)
- {
- Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement);
- }
-
- this.focusedElement = Keyboard.FocusedElement;
-
- if (this.focusedElement != null)
- {
- this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus;
- }
-
- this.canSizeY = true;
-
- this.galleryPanel.Width = double.NaN;
- this.scrollViewer.Height = double.NaN;
-
- var popupChild = this.DropDownPopup.Child as FrameworkElement;
- var heightDelta = popupChild.DesiredSize.Height - this.scrollViewer.DesiredSize.Height;
-
- var initialHeight = Math.Min(RibbonControl.GetControlWorkArea(this).Height * 2 / 3, this.MaxDropDownHeight);
-
- if (double.IsNaN(this.DropDownHeight) == false)
- {
- initialHeight = Math.Min(this.DropDownHeight, this.MaxDropDownHeight);
- }
-
- if (this.scrollViewer.DesiredSize.Height > initialHeight)
- {
- this.scrollViewer.Height = initialHeight;
- }
- else
- {
- initialHeight = this.scrollViewer.DesiredSize.Height;
- }
-
- var monitor = RibbonControl.GetControlMonitor(this);
- var delta = monitor.Bottom - this.PointToScreen(new Point()).Y - this.ActualHeight - initialHeight - heightDelta;
-
- if (delta >= 0)
- {
- this.ShowPopupOnTop = false;
- }
- else
- {
- var deltaTop = this.PointToScreen(new Point()).Y - initialHeight - heightDelta - monitor.Top;
-
- if (deltaTop > delta)
- {
- this.ShowPopupOnTop = true;
- }
- else
- {
- this.ShowPopupOnTop = false;
- }
-
- if (deltaTop < 0)
- {
- delta = Math.Max(Math.Abs(delta), Math.Abs(deltaTop));
-
- if (delta > this.galleryPanel.GetItemSize().Height)
- {
- this.scrollViewer.Height = delta;
- }
- else
- {
- this.canSizeY = false;
- this.scrollViewer.Height = this.galleryPanel.GetItemSize().Height;
- }
- }
- }
-
- popupChild.UpdateLayout();
- }
-
- ///
- /// Reports when a combo box's popup closes.
- ///
- /// The event data for the event.
- protected override void OnDropDownClosed(EventArgs e)
- {
- base.OnDropDownClosed(e);
- if (Mouse.Captured == this) Mouse.Capture(null);
- if (this.focusedElement != null) this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus;
- this.focusedElement = null;
- this.ShowPopupOnTop = false;
- this.galleryPanel.Width = double.NaN;
- this.scrollViewer.Height = double.NaN;
- }
-
- private void OnFocusedElementLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
- {
- if (this.focusedElement != null) this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus;
- this.focusedElement = Keyboard.FocusedElement;
- if (this.focusedElement != null)
- {
- this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus;
- if ((this.IsEditable) &&
- (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))))
- {
- this.SelectedItem = this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject);
- }
- }
- }
-
- ///
- /// Invoked when a attached routed event occurs.
- ///
- /// Event data.
- protected override void OnPreviewKeyDown(KeyEventArgs e)
- {
- if ((this.IsEditable) && ((e.Key == Key.Down) || (e.Key == Key.Up)) && (!this.IsDropDownOpen))
- {
- this.IsDropDownOpen = true;
- e.Handled = true;
- return;
- }
-
- base.OnPreviewKeyDown(e);
- }
-
- ///
- /// Invoked when a attached routed event occurs.
- ///
- /// Event data.
- protected override void OnKeyDown(KeyEventArgs e)
- {
- if (e.Key == Key.Down)
- {
- Debug.WriteLine("Down pressed. FocusedElement - " + Keyboard.FocusedElement);
- if ((this.Menu != null) && this.Menu.Items.Contains(this.Menu.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))
- {
- var indexOfMSelectedItem = this.Menu.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject);
- if (indexOfMSelectedItem != this.Menu.Items.Count - 1)
- {
- Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(indexOfMSelectedItem + 1) as IInputElement);
- }
- else
- {
- if ((this.Items.Count > 0) && (!this.IsEditable))
- {
- Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement);
- }
- else Keyboard.Focus(this.Menu.Items[0] as IInputElement);
- }
- }
- else if (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))
- {
- var indexOfSelectedItem = this.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject);
- if (indexOfSelectedItem != this.Items.Count - 1)
- {
- Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(indexOfSelectedItem + 1) as IInputElement);
- }
- else
- {
- if ((this.Menu != null) && (this.Menu.Items.Count > 0) && (!this.IsEditable)) Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement);
- else
- {
- Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement);
- }
- }
- }
- else if (this.SelectedItem != null) Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement);
- e.Handled = true;
- Debug.WriteLine("FocusedElement - " + Keyboard.FocusedElement);
- return;
- }
- else if (e.Key == Key.Up)
- {
- Debug.WriteLine("Up pressed. FocusedElement - " + Keyboard.FocusedElement);
- if ((this.Menu != null) && this.Menu.Items.Contains(this.Menu.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))
- {
- var indexOfMSelectedItem = this.Menu.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject);
- if (indexOfMSelectedItem != 0)
- {
- Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(indexOfMSelectedItem - 1) as IInputElement);
- }
- else
- {
- if ((this.Items.Count > 0) && (!this.IsEditable))
- {
- Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1) as IInputElement);
- }
- else Keyboard.Focus(this.Menu.Items[this.Menu.Items.Count - 1] as IInputElement);
- }
- }
- else if (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))
- {
- var indexOfSelectedItem = this.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject);
- if (indexOfSelectedItem != 0)
- {
- Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(indexOfSelectedItem - 1) as IInputElement);
- }
- else
- {
- if ((this.Menu != null) && (this.Menu.Items.Count > 0) && (!this.IsEditable)) Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(this.Menu.Items.Count - 1) as IInputElement);
- else
- {
- Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1) as IInputElement);
- }
- }
- }
- else if (this.SelectedItem != null) Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement);
- Debug.WriteLine("FocusedElement - " + Keyboard.FocusedElement);
- e.Handled = true;
- return;
- }
- else if ((e.Key == Key.Return) && (!this.IsEditable) && this.IsDropDownOpen)
- {
- var element = Keyboard.FocusedElement as DependencyObject;
-
- // only try to select if we got a focusedElement
- if (element != null)
- {
- var newSelectedIndex = this.ItemContainerGenerator.IndexFromContainer(element);
-
- // only set the selected index if the focused element was in a container in this combobox
- if (newSelectedIndex > -1)
- {
- this.SelectedIndex = newSelectedIndex;
- }
- }
- }
- base.OnKeyDown(e);
- }
-
- #endregion
-
- #region Methods
-
- ///
- /// Handles key tip pressed
- ///
- public virtual void OnKeyTipPressed()
- {
- this.Dispatcher.BeginInvoke(
- DispatcherPriority.Normal,
- (DispatcherOperationCallback)delegate(object arg)
- {
- var ctrl = (ComboBox)arg;
-
- // Edge case: Whole dropdown content is disabled
- if (ctrl.IsKeyboardFocusWithin == false)
- {
- Keyboard.Focus(ctrl);
- }
- return null;
- },
- this);
-
- if (!this.IsEditable)
- {
- this.IsDropDownOpen = true;
- }
- }
-
- ///
- /// Handles back navigation with KeyTips
- ///
- public void OnKeyTipBack()
- {
- }
-
- #endregion
-
- #region Private methods
-
- // Prevent reopenning of the dropdown menu (popup)
- private void OnContentBorderPreviewMouseDown(object sender, MouseButtonEventArgs e)
- {
- if (this.IsDropDownOpen)
- {
- this.IsDropDownOpen = false;
- e.Handled = true;
- }
- }
-
- // Handles resize both drag
- private void OnResizeBothDelta(object sender, DragDeltaEventArgs e)
- {
- // Set height
- this.SetDragHeight(e);
-
- // Set width
- this.menuPanel.Width = double.NaN;
- if (double.IsNaN(this.galleryPanel.Width))
- {
- this.galleryPanel.Width = this.galleryPanel.ActualWidth;
- }
-
- var monitorRight = RibbonControl.GetControlMonitor(this).Right;
- var popupChild = this.DropDownPopup.Child as FrameworkElement;
- var delta = monitorRight - this.PointToScreen(new Point()).X - popupChild.ActualWidth - e.HorizontalChange;
- var deltaX = popupChild.ActualWidth - this.galleryPanel.ActualWidth;
- var deltaBorders = this.dropDownBorder.ActualWidth - this.galleryPanel.ActualWidth;
-
- if (delta > 0)
- {
- this.galleryPanel.Width = Math.Max(0, Math.Max(this.galleryPanel.Width + e.HorizontalChange, this.ActualWidth - deltaBorders));
- }
- else
- {
- this.galleryPanel.Width = Math.Max(0, Math.Max(monitorRight - this.PointToScreen(new Point()).X - deltaX, this.ActualWidth - deltaBorders));
- }
- }
-
- // Handles resize vertical drag
- private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e)
- {
- this.SetDragHeight(e);
- }
-
- private void SetDragHeight(DragDeltaEventArgs e)
- {
- if (!this.canSizeY)
- {
- return;
- }
-
- if (double.IsNaN(this.scrollViewer.Height))
- {
- this.scrollViewer.Height = this.scrollViewer.ActualHeight;
- }
-
- if (this.ShowPopupOnTop)
- {
- var monitorTop = RibbonControl.GetControlMonitor(this).Top;
-
- // Calc shadow height
- var delta = this.PointToScreen(new Point()).Y - this.dropDownBorder.ActualHeight - e.VerticalChange - monitorTop;
- if (delta > 0)
- {
- this.scrollViewer.Height = Math.Max(0,
- Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight));
- }
- else
- {
- delta = this.PointToScreen(new Point()).Y - this.dropDownBorder.ActualHeight - monitorTop;
- this.scrollViewer.Height = Math.Max(0,
- Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + delta), this.MaxDropDownHeight));
- }
- }
- else
- {
- var monitorBottom = RibbonControl.GetControlMonitor(this).Bottom;
- var popupChild = this.DropDownPopup.Child as FrameworkElement;
- var delta = monitorBottom - this.PointToScreen(new Point()).Y - this.ActualHeight - popupChild.ActualHeight - e.VerticalChange;
- if (delta > 0)
- {
- this.scrollViewer.Height = Math.Max(0,
- Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight));
- }
- else
- {
- delta = monitorBottom - this.PointToScreen(new Point()).Y - this.ActualHeight - popupChild.ActualHeight;
- this.scrollViewer.Height = Math.Max(0,
- Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + delta), this.MaxDropDownHeight));
- }
- }
- }
-
- #endregion
- }
+ if (this.SelectedItem != null)
+ {
+ Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement);
+ }
+
+ this.focusedElement = Keyboard.FocusedElement;
+
+ if (this.focusedElement != null)
+ {
+ this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus;
+ }
+
+ this.canSizeY = true;
+
+ this.galleryPanel.Width = double.NaN;
+ this.scrollViewer.Height = double.NaN;
+
+ var popupChild = this.DropDownPopup.Child as FrameworkElement;
+ var heightDelta = popupChild.DesiredSize.Height - this.scrollViewer.DesiredSize.Height;
+
+ var initialHeight = Math.Min(RibbonControl.GetControlWorkArea(this).Height * 2 / 3, this.MaxDropDownHeight);
+
+ if (double.IsNaN(this.DropDownHeight) == false)
+ {
+ initialHeight = Math.Min(this.DropDownHeight, this.MaxDropDownHeight);
+ }
+
+ if (this.scrollViewer.DesiredSize.Height > initialHeight)
+ {
+ this.scrollViewer.Height = initialHeight;
+ }
+ else
+ {
+ initialHeight = this.scrollViewer.DesiredSize.Height;
+ }
+
+ var monitor = RibbonControl.GetControlMonitor(this);
+ var delta = monitor.Bottom - this.PointToScreen(new Point()).Y - this.ActualHeight - initialHeight - heightDelta;
+
+ if (delta >= 0)
+ {
+ this.ShowPopupOnTop = false;
+ }
+ else
+ {
+ var deltaTop = this.PointToScreen(new Point()).Y - initialHeight - heightDelta - monitor.Top;
+
+ if (deltaTop > delta)
+ {
+ this.ShowPopupOnTop = true;
+ }
+ else
+ {
+ this.ShowPopupOnTop = false;
+ }
+
+ if (deltaTop < 0)
+ {
+ delta = Math.Max(Math.Abs(delta), Math.Abs(deltaTop));
+
+ if (delta > this.galleryPanel.GetItemSize().Height)
+ {
+ this.scrollViewer.Height = delta;
+ }
+ else
+ {
+ this.canSizeY = false;
+ this.scrollViewer.Height = this.galleryPanel.GetItemSize().Height;
+ }
+ }
+ }
+
+ popupChild.UpdateLayout();
+ }
+
+ ///
+ /// Reports when a combo box's popup closes.
+ ///
+ /// The event data for the event.
+ protected override void OnDropDownClosed(EventArgs e)
+ {
+ base.OnDropDownClosed(e);
+ if (Mouse.Captured == this) Mouse.Capture(null);
+ if (this.focusedElement != null) this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus;
+ this.focusedElement = null;
+ this.ShowPopupOnTop = false;
+ this.galleryPanel.Width = double.NaN;
+ this.scrollViewer.Height = double.NaN;
+ }
+
+ private void OnFocusedElementLostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
+ {
+ if (this.focusedElement != null) this.focusedElement.LostKeyboardFocus -= this.OnFocusedElementLostKeyboardFocus;
+ this.focusedElement = Keyboard.FocusedElement;
+ if (this.focusedElement != null)
+ {
+ this.focusedElement.LostKeyboardFocus += this.OnFocusedElementLostKeyboardFocus;
+ if ((this.IsEditable) &&
+ (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject))))
+ {
+ this.SelectedItem = this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject);
+ }
+ }
+ }
+
+ ///
+ /// Invoked when a attached routed event occurs.
+ ///
+ /// Event data.
+ protected override void OnPreviewKeyDown(KeyEventArgs e)
+ {
+ if ((this.IsEditable) && ((e.Key == Key.Down) || (e.Key == Key.Up)) && (!this.IsDropDownOpen))
+ {
+ this.IsDropDownOpen = true;
+ e.Handled = true;
+ return;
+ }
+
+ base.OnPreviewKeyDown(e);
+ }
+
+ ///
+ /// Invoked when a attached routed event occurs.
+ ///
+ /// Event data.
+ protected override void OnKeyDown(KeyEventArgs e)
+ {
+ if (e.Key == Key.Down)
+ {
+ Debug.WriteLine("Down pressed. FocusedElement - " + Keyboard.FocusedElement);
+ if ((this.Menu != null) && this.Menu.Items.Contains(this.Menu.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))
+ {
+ var indexOfMSelectedItem = this.Menu.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject);
+ if (indexOfMSelectedItem != this.Menu.Items.Count - 1)
+ {
+ Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(indexOfMSelectedItem + 1) as IInputElement);
+ }
+ else
+ {
+ if ((this.Items.Count > 0) && (!this.IsEditable))
+ {
+ Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement);
+ }
+ else Keyboard.Focus(this.Menu.Items[0] as IInputElement);
+ }
+ }
+ else if (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))
+ {
+ var indexOfSelectedItem = this.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject);
+ if (indexOfSelectedItem != this.Items.Count - 1)
+ {
+ Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(indexOfSelectedItem + 1) as IInputElement);
+ }
+ else
+ {
+ if ((this.Menu != null) && (this.Menu.Items.Count > 0) && (!this.IsEditable)) Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement);
+ else
+ {
+ Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(0) as IInputElement);
+ }
+ }
+ }
+ else if (this.SelectedItem != null) Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement);
+ e.Handled = true;
+ Debug.WriteLine("FocusedElement - " + Keyboard.FocusedElement);
+ return;
+ }
+ else if (e.Key == Key.Up)
+ {
+ Debug.WriteLine("Up pressed. FocusedElement - " + Keyboard.FocusedElement);
+ if ((this.Menu != null) && this.Menu.Items.Contains(this.Menu.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))
+ {
+ var indexOfMSelectedItem = this.Menu.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject);
+ if (indexOfMSelectedItem != 0)
+ {
+ Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(indexOfMSelectedItem - 1) as IInputElement);
+ }
+ else
+ {
+ if ((this.Items.Count > 0) && (!this.IsEditable))
+ {
+ Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1) as IInputElement);
+ }
+ else Keyboard.Focus(this.Menu.Items[this.Menu.Items.Count - 1] as IInputElement);
+ }
+ }
+ else if (this.Items.Contains(this.ItemContainerGenerator.ItemFromContainer(Keyboard.FocusedElement as DependencyObject)))
+ {
+ var indexOfSelectedItem = this.ItemContainerGenerator.IndexFromContainer(Keyboard.FocusedElement as DependencyObject);
+ if (indexOfSelectedItem != 0)
+ {
+ Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(indexOfSelectedItem - 1) as IInputElement);
+ }
+ else
+ {
+ if ((this.Menu != null) && (this.Menu.Items.Count > 0) && (!this.IsEditable)) Keyboard.Focus(this.Menu.ItemContainerGenerator.ContainerFromIndex(this.Menu.Items.Count - 1) as IInputElement);
+ else
+ {
+ Keyboard.Focus(this.ItemContainerGenerator.ContainerFromIndex(this.Items.Count - 1) as IInputElement);
+ }
+ }
+ }
+ else if (this.SelectedItem != null) Keyboard.Focus(this.ItemContainerGenerator.ContainerFromItem(this.SelectedItem) as IInputElement);
+ Debug.WriteLine("FocusedElement - " + Keyboard.FocusedElement);
+ e.Handled = true;
+ return;
+ }
+ else if ((e.Key == Key.Return) && (!this.IsEditable) && this.IsDropDownOpen)
+ {
+ var element = Keyboard.FocusedElement as DependencyObject;
+
+ // only try to select if we got a focusedElement
+ if (element != null)
+ {
+ var newSelectedIndex = this.ItemContainerGenerator.IndexFromContainer(element);
+
+ // only set the selected index if the focused element was in a container in this combobox
+ if (newSelectedIndex > -1)
+ {
+ this.SelectedIndex = newSelectedIndex;
+ }
+ }
+ }
+ base.OnKeyDown(e);
+ }
+
+ #endregion
+
+ #region Methods
+
+ ///
+ /// Handles key tip pressed
+ ///
+ public virtual void OnKeyTipPressed()
+ {
+ this.Dispatcher.BeginInvoke(
+ DispatcherPriority.Normal,
+ (DispatcherOperationCallback)delegate (object arg)
+ {
+ var ctrl = (ComboBox)arg;
+
+ // Edge case: Whole dropdown content is disabled
+ if (ctrl.IsKeyboardFocusWithin == false)
+ {
+ Keyboard.Focus(ctrl);
+ }
+ return null;
+ },
+ this);
+
+ if (!this.IsEditable)
+ {
+ this.IsDropDownOpen = true;
+ }
+ }
+
+ ///
+ /// Handles back navigation with KeyTips
+ ///
+ public void OnKeyTipBack()
+ {
+ }
+
+ #endregion
+
+ #region Private methods
+
+ // Prevent reopenning of the dropdown menu (popup)
+ private void OnContentBorderPreviewMouseDown(object sender, MouseButtonEventArgs e)
+ {
+ if (this.IsDropDownOpen)
+ {
+ this.IsDropDownOpen = false;
+ e.Handled = true;
+ }
+ }
+
+ // Handles resize both drag
+ private void OnResizeBothDelta(object sender, DragDeltaEventArgs e)
+ {
+ // Set height
+ this.SetDragHeight(e);
+
+ // Set width
+ this.menuPanel.Width = double.NaN;
+ if (double.IsNaN(this.galleryPanel.Width))
+ {
+ this.galleryPanel.Width = this.galleryPanel.ActualWidth;
+ }
+
+ var monitorRight = RibbonControl.GetControlMonitor(this).Right;
+ var popupChild = this.DropDownPopup.Child as FrameworkElement;
+ var delta = monitorRight - this.PointToScreen(new Point()).X - popupChild.ActualWidth - e.HorizontalChange;
+ var deltaX = popupChild.ActualWidth - this.galleryPanel.ActualWidth;
+ var deltaBorders = this.dropDownBorder.ActualWidth - this.galleryPanel.ActualWidth;
+
+ if (delta > 0)
+ {
+ this.galleryPanel.Width = Math.Max(0, Math.Max(this.galleryPanel.Width + e.HorizontalChange, this.ActualWidth - deltaBorders));
+ }
+ else
+ {
+ this.galleryPanel.Width = Math.Max(0, Math.Max(monitorRight - this.PointToScreen(new Point()).X - deltaX, this.ActualWidth - deltaBorders));
+ }
+ }
+
+ // Handles resize vertical drag
+ private void OnResizeVerticalDelta(object sender, DragDeltaEventArgs e)
+ {
+ this.SetDragHeight(e);
+ }
+
+ private void SetDragHeight(DragDeltaEventArgs e)
+ {
+ if (!this.canSizeY)
+ {
+ return;
+ }
+
+ if (double.IsNaN(this.scrollViewer.Height))
+ {
+ this.scrollViewer.Height = this.scrollViewer.ActualHeight;
+ }
+
+ if (this.ShowPopupOnTop)
+ {
+ var monitorTop = RibbonControl.GetControlMonitor(this).Top;
+
+ // Calc shadow height
+ var delta = this.PointToScreen(new Point()).Y - this.dropDownBorder.ActualHeight - e.VerticalChange - monitorTop;
+ if (delta > 0)
+ {
+ this.scrollViewer.Height = Math.Max(0,
+ Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight));
+ }
+ else
+ {
+ delta = this.PointToScreen(new Point()).Y - this.dropDownBorder.ActualHeight - monitorTop;
+ this.scrollViewer.Height = Math.Max(0,
+ Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + delta), this.MaxDropDownHeight));
+ }
+ }
+ else
+ {
+ var monitorBottom = RibbonControl.GetControlMonitor(this).Bottom;
+ var popupChild = this.DropDownPopup.Child as FrameworkElement;
+ var delta = monitorBottom - this.PointToScreen(new Point()).Y - this.ActualHeight - popupChild.ActualHeight - e.VerticalChange;
+ if (delta > 0)
+ {
+ this.scrollViewer.Height = Math.Max(0,
+ Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + e.VerticalChange), this.MaxDropDownHeight));
+ }
+ else
+ {
+ delta = monitorBottom - this.PointToScreen(new Point()).Y - this.ActualHeight - popupChild.ActualHeight;
+ this.scrollViewer.Height = Math.Max(0,
+ Math.Min(Math.Max(this.galleryPanel.GetItemSize().Height, this.scrollViewer.Height + delta), this.MaxDropDownHeight));
+ }
+ }
+ }
+
+ #endregion
+ }
}
\ No newline at end of file
diff --git a/Fluent.Ribbon/Controls/GalleryGroupContainer.cs b/Fluent.Ribbon/Controls/GalleryGroupContainer.cs
index 9785aae58..b67428d03 100644
--- a/Fluent.Ribbon/Controls/GalleryGroupContainer.cs
+++ b/Fluent.Ribbon/Controls/GalleryGroupContainer.cs
@@ -14,11 +14,11 @@ public class GalleryGroupContainer : HeaderedItemsControl
{
#region Fields
- private Panel previousItemsPanel;
private int previousItemsCount;
- // Whether MaxWidth of the ItemsPanel needs to be updated
- private bool maxMinWidthNeedsToBeUpdated;
+ // Whether MinWidth/MaxWidth of the ItemsPanel needs to be updated
+ private bool minMaxWidthNeedsToBeUpdated = true;
+ private Panel itemsPanel;
#endregion
@@ -41,9 +41,9 @@ public bool IsHeadered
/// This enables animation, styling, binding, etc...
///
public static readonly DependencyProperty IsHeaderedProperty =
- DependencyProperty.Register("IsHeadered", typeof(bool),
+ DependencyProperty.Register("IsHeadered", typeof(bool),
typeof(GalleryGroupContainer), new UIPropertyMetadata(true));
-
+
#endregion
#region Orientation
@@ -66,7 +66,7 @@ public Orientation Orientation
typeof(GalleryGroupContainer), new UIPropertyMetadata(Orientation.Horizontal));
#endregion
-
+
#region ItemWidth
///
@@ -110,9 +110,9 @@ public double ItemHeight
typeof(GalleryGroupContainer), new UIPropertyMetadata(double.NaN));
#endregion
-
+
#region MinItemsInRow
-
+
///
/// Gets or sets minimum items quantity in row
///
@@ -130,14 +130,8 @@ public int MinItemsInRow
DependencyProperty.Register("MinItemsInRow", typeof(int),
typeof(GalleryGroupContainer), new UIPropertyMetadata(0, OnMaxMinItemsInRowChanged));
- static void OnMaxMinItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- GalleryGroupContainer galleryGroupContainer = (GalleryGroupContainer) d;
- galleryGroupContainer.maxMinWidthNeedsToBeUpdated = true;
- }
-
#endregion
-
+
#region MaxItemsInRow
///
@@ -159,6 +153,20 @@ public int MaxItemsInRow
#endregion
+ private Panel RealItemsPanel
+ {
+ get
+ {
+ return this.itemsPanel ?? (this.itemsPanel = FindItemsPanel(this));
+ }
+ }
+
+ private static void OnMaxMinItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var galleryGroupContainer = (GalleryGroupContainer)d;
+ galleryGroupContainer.minMaxWidthNeedsToBeUpdated = true;
+ }
+
#endregion
#region Initialization
@@ -169,47 +177,57 @@ public int MaxItemsInRow
static GalleryGroupContainer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(GalleryGroupContainer), new FrameworkPropertyMetadata(typeof(GalleryGroupContainer)));
- StyleProperty.OverrideMetadata(typeof(GalleryGroupContainer), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle)));
}
- // Coerce object style
- static object OnCoerceStyle(DependencyObject d, object basevalue)
+ ///
+ /// Invoked when the property changes.
+ ///
+ /// Old value of the property.New value of the property.
+ protected override void OnItemsPanelChanged(ItemsPanelTemplate oldItemsPanel, ItemsPanelTemplate newItemsPanel)
{
- if (basevalue == null)
- {
- basevalue = ((FrameworkElement)d).TryFindResource(typeof(GalleryGroupContainer));
- }
+ base.OnItemsPanelChanged(oldItemsPanel, newItemsPanel);
- return basevalue;
+ this.itemsPanel = null;
+ this.minMaxWidthNeedsToBeUpdated = true;
+ this.InvalidateMeasure();
}
-
+
#endregion
#region MaxWidth Updating
-
+
// Sets MaxWidth of the items panel based of ItemsInRow property
private void UpdateMinAndMaxWidth()
{
- this.maxMinWidthNeedsToBeUpdated = false;
+ if (this.minMaxWidthNeedsToBeUpdated == false)
+ {
+ return;
+ }
- var itemsPanel = FindItemsPanel(this);
- if (itemsPanel == null)
+ if (this.RealItemsPanel == null)
{
// Item's panel is not ready now
if (this.IsLoaded)
{
Debug.WriteLine("Panel with IsItemsHost = true is not found in GalleryGroupContainer (probably the style is not correct or haven't attached yet)");
}
+ else
+ {
+ // Prevent duplicate registration
+ this.Loaded -= this.HandleLoaded;
+ this.Loaded += this.HandleLoaded;
+ }
- this.Dispatcher.BeginInvoke((Action)this.InvalidateMeasure, DispatcherPriority.ContextIdle);
return;
}
+ this.minMaxWidthNeedsToBeUpdated = false;
+
if (this.Orientation == Orientation.Vertical)
{
// Min/Max is used for Horizontal layout only
- itemsPanel.MinWidth = 0;
- itemsPanel.MaxWidth = double.PositiveInfinity;
+ this.RealItemsPanel.MinWidth = 0;
+ this.RealItemsPanel.MaxWidth = double.PositiveInfinity;
return;
}
@@ -220,17 +238,29 @@ private void UpdateMinAndMaxWidth()
return;
}
- itemsPanel.MinWidth = Math.Min(this.Items.Count, this.MinItemsInRow) * itemWidth + 0.1;
- itemsPanel.MaxWidth = Math.Min(this.Items.Count, this.MaxItemsInRow) * itemWidth + 0.1;
+ this.RealItemsPanel.MinWidth = Math.Min(this.Items.Count, this.MinItemsInRow) * itemWidth + 0.1;
+ this.RealItemsPanel.MaxWidth = Math.Min(this.Items.Count, this.MaxItemsInRow) * itemWidth + 0.1;
}
-
+
+ private void HandleLoaded(object sender, RoutedEventArgs e)
+ {
+ this.Loaded -= this.HandleLoaded;
+
+ if (this.minMaxWidthNeedsToBeUpdated == false)
+ {
+ return;
+ }
+
+ this.InvalidateMeasure();
+ }
+
///
/// Determinates item's size (return Size.Empty in case of it is not possible)
///
///
public Size GetItemSize()
{
- if (!double.IsNaN(this.ItemWidth)
+ if (!double.IsNaN(this.ItemWidth)
&& !double.IsNaN(this.ItemHeight))
{
return new Size(this.ItemWidth, this.ItemHeight);
@@ -290,16 +320,14 @@ private static Panel FindItemsPanel(DependencyObject obj)
/// The maximum size that the method can return.
protected override Size MeasureOverride(Size constraint)
{
- var panel = FindItemsPanel(this);
- if (panel != this.previousItemsPanel
- || this.previousItemsCount != this.Items.Count
- || this.maxMinWidthNeedsToBeUpdated)
+ if (this.previousItemsCount != this.Items.Count
+ || this.minMaxWidthNeedsToBeUpdated)
{
// Track ItemsPanel changing
- this.previousItemsPanel = panel;
this.previousItemsCount = this.Items.Count;
this.UpdateMinAndMaxWidth();
}
+
return base.MeasureOverride(constraint);
}
}
diff --git a/Fluent.Ribbon/Controls/GalleryGroupIcon.cs b/Fluent.Ribbon/Controls/GalleryGroupIcon.cs
deleted file mode 100644
index 6b9237b9b..000000000
--- a/Fluent.Ribbon/Controls/GalleryGroupIcon.cs
+++ /dev/null
@@ -1,46 +0,0 @@
-using System.Windows;
-using System.Windows.Media;
-
-namespace Fluent
-{
- ///
- /// Represents gallery group icon definition
- ///
- public class GalleryGroupIcon : DependencyObject
- {
- ///
- /// Gets or sets group name
- ///
- public string GroupName
- {
- get { return (string)this.GetValue(GroupNameProperty); }
- set { this.SetValue(GroupNameProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for GroupName.
- /// This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty GroupNameProperty =
- DependencyProperty.Register("GroupName", typeof(string),
- typeof(GalleryGroupIcon), new UIPropertyMetadata(null));
-
-
- ///
- /// Gets or sets group icon
- ///
- public ImageSource Icon
- {
- get { return (ImageSource)this.GetValue(IconProperty); }
- set { this.SetValue(IconProperty, value); }
- }
-
- ///
- /// Using a DependencyProperty as the backing store for Icon.
- /// This enables animation, styling, binding, etc...
- ///
- public static readonly DependencyProperty IconProperty =
- DependencyProperty.Register("Icon", typeof(ImageSource), typeof(GalleryGroupIcon),
- new UIPropertyMetadata(null));
- }
-}
\ No newline at end of file
diff --git a/Fluent.Ribbon/Controls/GalleryPanel.cs b/Fluent.Ribbon/Controls/GalleryPanel.cs
index d47648ee3..43ac73538 100644
--- a/Fluent.Ribbon/Controls/GalleryPanel.cs
+++ b/Fluent.Ribbon/Controls/GalleryPanel.cs
@@ -25,7 +25,7 @@ public class GalleryPanel : VirtualizingStackPanel
private readonly List galleryGroupContainers = new List();
// Designate that gallery panel must be refreshed its groups
- private bool haveToBeRefreshed;
+ private bool needsRefresh = true;
// Group name resolver
private Func
public static readonly DependencyProperty MinItemsInRowProperty =
- DependencyProperty.Register("MinItemsInRow", typeof(int), typeof(GalleryPanel), new UIPropertyMetadata((int)1));
+ DependencyProperty.Register("MinItemsInRow", typeof(int), typeof(GalleryPanel), new UIPropertyMetadata(1));
#endregion
@@ -359,28 +359,24 @@ public Size GetItemSize()
private void Invalidate()
{
- if (this.haveToBeRefreshed)
+ if (this.needsRefresh)
{
return;
}
- this.haveToBeRefreshed = true;
- this.Dispatcher.BeginInvoke((Action)this.RefreshDispatchered, DispatcherPriority.Send);
+ this.needsRefresh = true;
+ this.Dispatcher.BeginInvoke((Action)this.Refresh, DispatcherPriority.Send);
}
- private void RefreshDispatchered()
+ private void Refresh()
{
- if (this.haveToBeRefreshed == false)
+ if (this.needsRefresh == false)
{
return;
}
- this.Refresh();
- this.haveToBeRefreshed = false;
- }
+ this.needsRefresh = false;
- private void Refresh()
- {
if (this.itemContainerGeneratorAction == null)
{
this.itemContainerGeneratorAction = new ItemContainerGeneratorAction((ItemContainerGenerator)this.ItemContainerGenerator, this.Refresh);
@@ -429,21 +425,18 @@ private void Refresh()
propertyValue = "Undefined";
}
- // Make invisible if it is not in filter (or is not grouped)
- if (this.IsGrouped == false
- || (filter != null && filter.Contains(propertyValue) == false))
- {
- item.Measure(new Size(0, 0));
- item.Arrange(new Rect(0, 0, 0, 0));
- }
-
- // Skip if it is not in filter
- if (filter != null
+ // Make invisible if it is not in filter
+ if (this.IsGrouped
+ && filter != null
&& filter.Contains(propertyValue) == false)
{
+ item.Visibility = Visibility.Collapsed;
continue;
}
+ // Make all not filtered items visible
+ item.Visibility = Visibility.Visible;
+
// To put all items in one group in case of IsGrouped = False
if (this.IsGrouped == false)
{
@@ -502,6 +495,8 @@ protected override Size MeasureOverride(Size availableSize)
{
var baseSize = base.MeasureOverride(availableSize);
+ this.Refresh();
+
if (this.galleryGroupContainers.Count == 0)
{
return baseSize;
@@ -531,6 +526,8 @@ protected override Size ArrangeOverride(Size finalSize)
{
var baseSize = base.ArrangeOverride(finalSize);
+ this.Refresh();
+
if (this.galleryGroupContainers.Count == 0)
{
return baseSize;
diff --git a/Fluent.Ribbon/Controls/InRibbonGallery.cs b/Fluent.Ribbon/Controls/InRibbonGallery.cs
index 27d4a9c53..86f3651aa 100644
--- a/Fluent.Ribbon/Controls/InRibbonGallery.cs
+++ b/Fluent.Ribbon/Controls/InRibbonGallery.cs
@@ -746,6 +746,19 @@ public int MaxItemsInRow
public static readonly DependencyProperty MaxItemsInRowProperty =
DependencyProperty.Register("MaxItemsInRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(8, OnMaxItemsInRowChanged));
+ private static void OnMaxItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ var gal = (InRibbonGallery)d;
+ var maxItemsInRow = (int)e.NewValue;
+
+ if (gal.IsDropDownOpen == false
+ && gal.galleryPanel != null
+ && gal.galleryPanel.MaxItemsInRow < maxItemsInRow)
+ {
+ gal.galleryPanel.MaxItemsInRow = maxItemsInRow;
+ }
+ }
+
///
/// Gets or sets min count of items in row
///
@@ -760,19 +773,18 @@ public int MinItemsInRow
/// This enables animation, styling, binding, etc...
///
public static readonly DependencyProperty MinItemsInRowProperty =
- DependencyProperty.Register("MinItemsInRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(1));
+ DependencyProperty.Register("MinItemsInRow", typeof(int), typeof(InRibbonGallery), new UIPropertyMetadata(1, OnMinItemsInRowChanged));
- private static void OnMaxItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ private static void OnMinItemsInRowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var gal = (InRibbonGallery)d;
var minItemsInRow = (int)e.NewValue;
if (gal.IsDropDownOpen == false
&& gal.galleryPanel != null
- && gal.galleryPanel.MinItemsInRow < minItemsInRow)
+ && gal.galleryPanel.MinItemsInRow > minItemsInRow)
{
gal.galleryPanel.MinItemsInRow = minItemsInRow;
- gal.galleryPanel.MaxItemsInRow = minItemsInRow;
}
}
@@ -1110,8 +1122,9 @@ public override void OnApplyTemplate()
if (this.galleryPanel != null)
{
- this.galleryPanel.MinItemsInRow = this.MaxItemsInRow;
+ this.galleryPanel.MinItemsInRow = this.MinItemsInRow;
this.galleryPanel.MaxItemsInRow = this.MaxItemsInRow;
+ this.galleryPanel.UpdateMinAndMaxWidth();
}
this.snappedImage = this.GetTemplateChild("PART_FakeImage") as Image;
@@ -1139,6 +1152,8 @@ private void ForceContentRefreshToFixLayout()
this.controlPresenter.Content = null;
this.controlPresenter.Content = this.galleryPanel;
+
+ this.galleryPanel.UpdateMinAndMaxWidth();
}
private void OnPopupPreviewMouseUp(object sender, MouseButtonEventArgs e)
@@ -1172,14 +1187,15 @@ private void OnDropDownClick(object sender, RoutedEventArgs e)
// Handles drop down opened
private void OnDropDownClosed(object sender, EventArgs e)
{
- this.galleryPanel.Width = double.NaN;
+ this.popupControlPresenter.Content = null;
+ this.controlPresenter.Content = this.galleryPanel;
+
this.galleryPanel.IsGrouped = false;
this.galleryPanel.MinItemsInRow = this.MinItemsInRow;
this.galleryPanel.MaxItemsInRow = this.MaxItemsInRow;
+ this.galleryPanel.Width = double.NaN;
this.galleryPanel.UpdateMinAndMaxWidth();
- this.popupControlPresenter.Content = null;
- this.controlPresenter.Content = this.galleryPanel;
this.Dispatcher.BeginInvoke(DispatcherPriority.SystemIdle, (ThreadStart)(() =>
{
if (this.quickAccessGallery == null
@@ -1212,16 +1228,15 @@ private void OnDropDownOpened(object sender, EventArgs e)
this.controlPresenter.Content = null;
this.popupControlPresenter.Content = this.galleryPanel;
- this.galleryPanel.Width = double.NaN;
- this.scrollViewer.Height = double.NaN;
-
- this.DropDownOpened?.Invoke(this, e);
+ this.galleryPanel.IsGrouped = true;
this.galleryPanel.MinItemsInRow = this.MinItemsInDropDownRow;
this.galleryPanel.MaxItemsInRow = this.MaxItemsInDropDownRow;
+ this.galleryPanel.Width = double.NaN;
this.galleryPanel.UpdateMinAndMaxWidth();
- this.galleryPanel.IsGrouped = true;
+ this.DropDownOpened?.Invoke(this, e);
+
this.dropDownButton.IsChecked = true;
this.canOpenDropDown = false;
diff --git a/Fluent.Ribbon/Controls/RadioButton.cs b/Fluent.Ribbon/Controls/RadioButton.cs
index 85bd66827..a783949d4 100644
--- a/Fluent.Ribbon/Controls/RadioButton.cs
+++ b/Fluent.Ribbon/Controls/RadioButton.cs
@@ -98,7 +98,7 @@ public object Header
///
public object Icon
{
- get { return (ImageSource)this.GetValue(IconProperty); }
+ get { return this.GetValue(IconProperty); }
set { this.SetValue(IconProperty, value); }
}
@@ -109,11 +109,19 @@ public object Icon
private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
- RadioButton element = d as RadioButton;
- FrameworkElement oldElement = e.OldValue as FrameworkElement;
- if (oldElement != null) element.RemoveLogicalChild(oldElement);
- FrameworkElement newElement = e.NewValue as FrameworkElement;
- if (newElement != null) element.AddLogicalChild(newElement);
+ var element = (RadioButton)d;
+
+ var oldElement = e.OldValue as FrameworkElement;
+ if (oldElement != null)
+ {
+ element.RemoveLogicalChild(oldElement);
+ }
+
+ var newElement = e.NewValue as FrameworkElement;
+ if (newElement != null)
+ {
+ element.AddLogicalChild(newElement);
+ }
}
#endregion
@@ -123,9 +131,9 @@ private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedE
///
/// Gets or sets button large icon
///
- public ImageSource LargeIcon
+ public object LargeIcon
{
- get { return (ImageSource)this.GetValue(LargeIconProperty); }
+ get { return this.GetValue(LargeIconProperty); }
set { this.SetValue(LargeIconProperty, value); }
}
@@ -133,9 +141,7 @@ public ImageSource LargeIcon
/// Using a DependencyProperty as the backing store for SmallIcon.
/// This enables animation, styling, binding, etc...
///
- public static readonly DependencyProperty LargeIconProperty =
- DependencyProperty.Register("LargeIcon", typeof(ImageSource),
- typeof(RadioButton), new UIPropertyMetadata(null));
+ public static readonly DependencyProperty LargeIconProperty = DependencyProperty.Register("LargeIcon", typeof(object), typeof(RadioButton), new UIPropertyMetadata(null));
#endregion
@@ -149,23 +155,10 @@ public ImageSource LargeIcon
[SuppressMessage("Microsoft.Performance", "CA1810")]
static RadioButton()
{
- Type type = typeof(RadioButton);
+ var type = typeof(RadioButton);
DefaultStyleKeyProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(type));
ContextMenuService.Attach(type);
ToolTipService.Attach(type);
- StyleProperty.OverrideMetadata(type, new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle)));
- }
-
- // Coerce object style
- static object OnCoerceStyle(DependencyObject d, object basevalue)
- {
- if (basevalue == null)
- {
- //basevalue = (d as FrameworkElement).TryFindResource(typeof(QuickAccessToolBar));
- basevalue = (d as FrameworkElement).TryFindResource(typeof(RadioButton));
- }
-
- return basevalue;
}
///
@@ -188,7 +181,7 @@ public RadioButton()
/// Control which represents shortcut item
public virtual FrameworkElement CreateQuickAccessItem()
{
- RadioButton button = new RadioButton();
+ var button = new RadioButton();
RibbonControl.Bind(this, button, "IsChecked", IsCheckedProperty, BindingMode.TwoWay);
button.Click += ((sender, e) => this.RaiseEvent(e));
diff --git a/Fluent.Ribbon/Controls/Ribbon.cs b/Fluent.Ribbon/Controls/Ribbon.cs
index 91a8d3598..aaf8a954b 100644
--- a/Fluent.Ribbon/Controls/Ribbon.cs
+++ b/Fluent.Ribbon/Controls/Ribbon.cs
@@ -21,6 +21,7 @@ namespace Fluent
{
using System.ComponentModel;
using System.Windows.Threading;
+ using ControlzEx.Microsoft.Windows.Shell;
using Fluent.Extensions;
// TODO: improve style parts naming & using
@@ -1051,8 +1052,10 @@ private static void OnIsMinimizedChanged(DependencyObject d, DependencyPropertyC
private static void OnCanMinimizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var ribbon = (Ribbon)d;
-
- ribbon.TabControl.CanMinimize = ribbon.CanMinimize;
+ if (ribbon.TabControl != null)
+ {
+ ribbon.TabControl.CanMinimize = ribbon.CanMinimize;
+ }
}
///
@@ -1414,6 +1417,8 @@ public Ribbon()
this.VerticalAlignment = VerticalAlignment.Top;
KeyboardNavigation.SetDirectionalNavigation(this, KeyboardNavigationMode.Contained);
+ WindowChrome.SetIsHitTestVisibleInChrome(this, true);
+
this.keyTipService = new KeyTipService(this);
this.Loaded += this.OnLoaded;
diff --git a/Fluent.Ribbon/Controls/RibbonControl.cs b/Fluent.Ribbon/Controls/RibbonControl.cs
index ed66dc330..b15e589e8 100644
--- a/Fluent.Ribbon/Controls/RibbonControl.cs
+++ b/Fluent.Ribbon/Controls/RibbonControl.cs
@@ -73,16 +73,23 @@ public object Icon
///
/// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc...
///
- public static readonly DependencyProperty IconProperty =
- DependencyProperty.Register("Icon", typeof(object), typeof(RibbonControl), new UIPropertyMetadata(null, OnIconChanged));
+ public static readonly DependencyProperty IconProperty = DependencyProperty.Register("Icon", typeof(object), typeof(RibbonControl), new UIPropertyMetadata(null, OnIconChanged));
private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
- RibbonControl element = d as RibbonControl;
- FrameworkElement oldElement = e.OldValue as FrameworkElement;
- if (oldElement != null) element.RemoveLogicalChild(oldElement);
- FrameworkElement newElement = e.NewValue as FrameworkElement;
- if (newElement != null) element.AddLogicalChild(newElement);
+ var element = (RibbonControl)d;
+
+ var oldElement = e.OldValue as FrameworkElement;
+ if (oldElement != null)
+ {
+ element.RemoveLogicalChild(oldElement);
+ }
+
+ var newElement = e.NewValue as FrameworkElement;
+ if (newElement != null)
+ {
+ element.AddLogicalChild(newElement);
+ }
}
#endregion
@@ -179,7 +186,7 @@ private static void OnCommandChanged(DependencyObject d, DependencyPropertyChang
newCommand.CanExecuteChanged += control.OnCommandCanExecuteChanged;
var routedUiCommand = e.NewValue as RoutedUICommand;
- if (routedUiCommand != null
+ if (routedUiCommand != null
&& control.Header == null)
{
control.Header = routedUiCommand.Text;
@@ -200,7 +207,7 @@ private void OnCommandCanExecuteChanged(object sender, EventArgs e)
private void UpdateCanExecute()
{
- var canExecute = this.Command != null
+ var canExecute = this.Command != null
&& this.CanExecuteCommand();
if (this.currentCanExecute != canExecute)
@@ -371,7 +378,7 @@ public static void BindQuickAccessItem(FrameworkElement source, FrameworkElement
rect.Width = 16;
rect.Height = 16;
rect.Fill = new VisualBrush(iconVisual);
- ((IRibbonControl) element).Icon = rect;
+ ((IRibbonControl)element).Icon = rect;
}
else
{
diff --git a/Fluent.Ribbon/Controls/RibbonGroupBox.cs b/Fluent.Ribbon/Controls/RibbonGroupBox.cs
index c42f9b01b..ccec98f62 100644
--- a/Fluent.Ribbon/Controls/RibbonGroupBox.cs
+++ b/Fluent.Ribbon/Controls/RibbonGroupBox.cs
@@ -25,7 +25,7 @@ namespace Fluent
[TemplatePart(Name = "PART_Popup", Type = typeof(Popup))]
[TemplatePart(Name = "PART_UpPanel", Type = typeof(Panel))]
public class RibbonGroupBox : ItemsControl, IQuickAccessItemProvider, IDropDownControl, IKeyTipedControl, IHeaderedControl
- {
+ {
#region Fields
// up part
@@ -35,7 +35,7 @@ public class RibbonGroupBox : ItemsControl, IQuickAccessItemProvider, IDropDownC
// Freezed image (created during snapping)
private Image snappedImage;
-
+
// Is visual currently snapped
private bool isSnapped;
@@ -303,7 +303,7 @@ static void OnDialogLauncherButtonKeyTipKeysChanged(DependencyObject d, Dependen
///
public object LauncherIcon
{
- get { return (ImageSource)this.GetValue(LauncherIconProperty); }
+ get { return this.GetValue(LauncherIconProperty); }
set { this.SetValue(LauncherIconProperty, value); }
}
@@ -516,7 +516,6 @@ protected override IEnumerator LogicalChildren
/// Gets or sets icon
///
public object Icon
- //public ImageSource Icon
{
get { return this.GetValue(IconProperty); }
set { this.SetValue(IconProperty, value); }
@@ -525,8 +524,7 @@ public object Icon
///
/// Using a DependencyProperty as the backing store for Icon. This enables animation, styling, binding, etc...
///
- public static readonly DependencyProperty IconProperty =
- RibbonControl.IconProperty.AddOwner(typeof(RibbonGroupBox), new UIPropertyMetadata(null, OnIconChanged));
+ public static readonly DependencyProperty IconProperty = RibbonControl.IconProperty.AddOwner(typeof(RibbonGroupBox), new UIPropertyMetadata(null, OnIconChanged));
private static void OnIconChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
@@ -917,11 +915,11 @@ protected override void OnChildDesiredSizeChanged(UIElement child)
private StateScale GetCurrentIntermediateStateScale()
{
- var stateScale = new StateScale
- {
- Scale = this.ScaleIntermediate,
- State = this.StateIntermediate
- };
+ var stateScale = new StateScale
+ {
+ Scale = this.ScaleIntermediate,
+ State = this.StateIntermediate
+ };
return stateScale;
}
@@ -996,7 +994,7 @@ public FrameworkElement CreateQuickAccessItem()
groupBox.DropDownOpened += this.OnQuickAccessOpened;
groupBox.DropDownClosed += this.OnQuickAccessClosed;
-
+
groupBox.State = RibbonGroupBoxState.QuickAccess;
RibbonControl.Bind(this, groupBox, "ItemTemplateSelector", ItemTemplateSelectorProperty, BindingMode.OneWay);
@@ -1099,7 +1097,7 @@ public bool CanAddToQuickAccessToolBar
/// Using a DependencyProperty as the backing store for CanAddToQuickAccessToolBar. This enables animation, styling, binding, etc...
///
public static readonly DependencyProperty CanAddToQuickAccessToolBarProperty =
- DependencyProperty.Register("CanAddToQuickAccessToolBar", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged));
+ DependencyProperty.Register("CanAddToQuickAccessToolBar", typeof(bool), typeof(RibbonGroupBox), new UIPropertyMetadata(true, RibbonControl.OnCanAddToQuickAccessToolbarChanged));
#endregion
diff --git a/Fluent.Ribbon/Controls/RibbonItemsControl.cs b/Fluent.Ribbon/Controls/RibbonItemsControl.cs
index 316ba26af..40278a622 100644
--- a/Fluent.Ribbon/Controls/RibbonItemsControl.cs
+++ b/Fluent.Ribbon/Controls/RibbonItemsControl.cs
@@ -3,7 +3,6 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Markup;
-using System.Windows.Media;
namespace Fluent
{
@@ -96,7 +95,7 @@ public object Header
///
public object Icon
{
- get { return (ImageSource)this.GetValue(IconProperty); }
+ get { return this.GetValue(IconProperty); }
set { this.SetValue(IconProperty, value); }
}
diff --git a/Fluent.Ribbon/Controls/RibbonTabControl.cs b/Fluent.Ribbon/Controls/RibbonTabControl.cs
index c3f718a51..51a6f4226 100644
--- a/Fluent.Ribbon/Controls/RibbonTabControl.cs
+++ b/Fluent.Ribbon/Controls/RibbonTabControl.cs
@@ -126,7 +126,7 @@ public bool CanMinimize
///
/// Using a DependencyProperty as the backing store for . This enables animation, styling, binding, etc...
///
- public static readonly DependencyProperty CanMinimizeProperty = DependencyProperty.Register("CanMinimize", typeof(bool), typeof(RibbonTabControl), new UIPropertyMetadata(true, OnCanMinimizeChanged));
+ public static readonly DependencyProperty CanMinimizeProperty = DependencyProperty.Register("CanMinimize", typeof(bool), typeof(RibbonTabControl), new UIPropertyMetadata(true));
///
@@ -670,25 +670,6 @@ private void OnGeneratorStatusChanged(object sender, EventArgs e)
}
}
- // Handles CanMinimizeChanges
- private static void OnCanMinimizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
- {
- var tab = (RibbonTabControl)d;
- var toggleButton = tab.Template.FindName("PART_MinimizeButton", tab) as Fluent.ToggleButton;
- if (toggleButton != null)
- {
- if (tab.CanMinimize)
- {
-
- toggleButton.Visibility = Visibility.Visible;
- }
- else
- {
- toggleButton.Visibility = Visibility.Collapsed;
- }
- }
- }
-
// Handles IsMinimized changed
private static void OnMinimizedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
diff --git a/Fluent.Ribbon/Controls/RibbonWindow.cs b/Fluent.Ribbon/Controls/RibbonWindow.cs
index 134a37b86..d4037a5f4 100644
--- a/Fluent.Ribbon/Controls/RibbonWindow.cs
+++ b/Fluent.Ribbon/Controls/RibbonWindow.cs
@@ -7,7 +7,7 @@
using System.Windows.Input;
using System.Windows.Interactivity;
using ControlzEx.Behaviors;
-
+
using Fluent.Extensions;
using Fluent.Helpers;
@@ -58,7 +58,7 @@ public Thickness ResizeBorderThickness
/// Using a DependencyProperty as the backing store for ResizeBorderTickness. This enables animation, styling, binding, etc...
///
public static readonly DependencyProperty ResizeBorderThicknessProperty =
- DependencyProperty.Register("ResizeBorderThickness", typeof(Thickness), typeof(RibbonWindow), new UIPropertyMetadata(WindowChromeBehavior.ResizeBorderThicknessProperty.DefaultMetadata.DefaultValue));
+ DependencyProperty.Register("ResizeBorderThickness", typeof(Thickness), typeof(RibbonWindow), new UIPropertyMetadata(new Thickness(8D)));
///
/// Gets or sets glass border thickness
@@ -220,6 +220,9 @@ private static object OnCoerceStyle(DependencyObject d, object basevalue)
public RibbonWindow()
{
this.SizeChanged += this.OnSizeChanged;
+
+ // WindowChrome initialization has to occur in constructor. Otherwise the load event is fired early.
+ this.InitializeWindowChromeBehavior();
}
#endregion
@@ -235,14 +238,12 @@ protected override void OnSourceInitialized(EventArgs e)
base.OnSourceInitialized(e);
this.UpdateCanUseDwm();
-
- this.InitializeWindowChromeBehavior();
}
///
/// Initializes the WindowChromeBehavior which is needed to render the custom WindowChrome
///
- protected virtual void InitializeWindowChromeBehavior()
+ private void InitializeWindowChromeBehavior()
{
var behavior = new WindowChromeBehavior();
BindingOperations.SetBinding(behavior, WindowChromeBehavior.CaptionHeightProperty, new Binding { Path = new PropertyPath(RibbonProperties.TitleBarHeightProperty), Source = this });
@@ -253,22 +254,6 @@ protected virtual void InitializeWindowChromeBehavior()
Interaction.GetBehaviors(this).Add(behavior);
}
- ///
- /// Called when the property changes.
- ///
- /// A reference to the root of the old content tree.A reference to the root of the new content tree.
- protected override void OnContentChanged(object oldContent, object newContent)
- {
- base.OnContentChanged(oldContent, newContent);
-
- var content = newContent as IInputElement;
-
- if (content != null)
- {
- WindowChrome.SetIsHitTestVisibleInChrome(content, true);
- }
- }
-
#endregion
private static void OnDontUseDwmChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
@@ -308,8 +293,6 @@ private void UpdateCanUseDwm()
&& this.DontUseDwm == false;
}
- #region Metro
-
///
/// When overridden in a derived class, is invoked whenever application code or internal processes call .
///
@@ -329,28 +312,15 @@ public override void OnApplyTemplate()
this.WindowCommands = new WindowCommands();
}
- this.iconImage = this.GetTemplateChild(PART_Icon) as FrameworkElement;
+ this.iconImage = this.GetPart(PART_Icon);
if (this.iconImage != null)
{
- WindowChrome.SetIsHitTestVisibleInChrome(this.iconImage, true);
-
this.iconImage.MouseDown += this.HandleIconMouseDown;
}
- var partContentPresenter = this.GetTemplateChild(PART_ContentPresenter) as UIElement;
-
- if (partContentPresenter != null)
- {
- WindowChrome.SetIsHitTestVisibleInChrome(partContentPresenter, true);
- }
-
- var partWindowCommands = this.GetTemplateChild(PART_WindowCommands) as UIElement;
-
- if (partWindowCommands != null)
- {
- WindowChrome.SetIsHitTestVisibleInChrome(partWindowCommands, true);
- }
+ this.GetPart(PART_Icon)?.SetValue(WindowChrome.IsHitTestVisibleInChromeProperty, true);
+ this.GetPart(PART_WindowCommands)?.SetValue(WindowChrome.IsHitTestVisibleInChromeProperty, true);
}
///
@@ -394,6 +364,15 @@ private void HandleIconMouseDown(object sender, MouseButtonEventArgs e)
}
}
- #endregion
+ ///
+ /// Gets the template child with the given name.
+ ///
+ /// The interface type inheirted from DependencyObject.
+ /// The name of the template child.
+ internal T GetPart(string name)
+ where T : DependencyObject
+ {
+ return this.GetTemplateChild(name) as T;
+ }
}
}
\ No newline at end of file
diff --git a/Fluent.Ribbon/Controls/TwoLineLabel.cs b/Fluent.Ribbon/Controls/TwoLineLabel.cs
index b93bb0810..6b7880f20 100644
--- a/Fluent.Ribbon/Controls/TwoLineLabel.cs
+++ b/Fluent.Ribbon/Controls/TwoLineLabel.cs
@@ -1,18 +1,22 @@
-using System;
-using System.Diagnostics.CodeAnalysis;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Documents;
-
-namespace Fluent
+namespace Fluent
{
+ using System;
+ using System.ComponentModel;
+ using System.Diagnostics.CodeAnalysis;
+ using System.Windows;
+ using System.Windows.Controls;
+ using System.Windows.Documents;
+ using System.Windows.Markup;
+
///
/// Represents specific label to use in particular ribbon controls
///
+ [DefaultProperty(nameof(Text))]
+ [ContentProperty(nameof(Text))]
[TemplatePart(Name = "PART_TextRun", Type = typeof(TextBlock))]
[TemplatePart(Name = "PART_TextRun2", Type = typeof(TextBlock))]
[TemplatePart(Name = "PART_Glyph", Type = typeof(InlineUIContainer))]
- public class TwoLineLabel: Control
+ public class TwoLineLabel : Control
{
#region Fields
@@ -41,7 +45,7 @@ public bool HasTwoLines
/// This enables animation, styling, binding, etc...
///
public static readonly DependencyProperty HasTwoLinesProperty =
- DependencyProperty.Register("HasTwoLines", typeof(bool), typeof(TwoLineLabel), new UIPropertyMetadata(true,OnHasTwoLinesChanged));
+ DependencyProperty.Register("HasTwoLines", typeof(bool), typeof(TwoLineLabel), new UIPropertyMetadata(true, OnHasTwoLinesChanged));
///
/// Handles HasTwoLines property changes
@@ -50,7 +54,7 @@ public bool HasTwoLines
/// The event data
private static void OnHasTwoLinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
- (d as TwoLineLabel).UpdateTextRun();
+ ((TwoLineLabel)d).UpdateTextRun();
}
///
@@ -75,7 +79,7 @@ public bool HasGlyph
/// The event data
private static void OnHasGlyphChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
- (d as TwoLineLabel).UpdateTextRun();
+ ((TwoLineLabel)d).UpdateTextRun();
}
///
@@ -91,7 +95,7 @@ public string Text
/// Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc...
///
public static readonly DependencyProperty TextProperty =
- DependencyProperty.Register("Text", typeof(string), typeof(TwoLineLabel), new UIPropertyMetadata("TwoLineLabel", OnTextChanged));
+ DependencyProperty.Register("Text", typeof(string), typeof(TwoLineLabel), new UIPropertyMetadata(string.Empty, OnTextChanged));
#endregion
@@ -104,11 +108,11 @@ public string Text
static TwoLineLabel()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(TwoLineLabel), new FrameworkPropertyMetadata(typeof(TwoLineLabel)));
- StyleProperty.OverrideMetadata(typeof(TwoLineLabel), new FrameworkPropertyMetadata(null, new CoerceValueCallback(OnCoerceStyle)));
+ StyleProperty.OverrideMetadata(typeof(TwoLineLabel), new FrameworkPropertyMetadata(null, OnCoerceStyle));
}
// Coerce object style
- static object OnCoerceStyle(DependencyObject d, object basevalue)
+ private static object OnCoerceStyle(DependencyObject d, object basevalue)
{
if (basevalue == null)
{
@@ -152,8 +156,8 @@ public override void OnApplyTemplate()
/// The event data
private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
- TwoLineLabel label = d as TwoLineLabel;
- label.UpdateTextRun();
+ var label = (TwoLineLabel)d;
+ label?.UpdateTextRun();
}
#endregion
@@ -163,59 +167,69 @@ private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedE
///
/// Updates text run adds newline if HasTwoLines == true
///
- void UpdateTextRun()
+ private void UpdateTextRun()
{
- if ((this.textRun != null)&&(this.textRun2 != null)&&(this.Text != null))
+ if (this.textRun == null
+ || this.textRun2 == null)
+ {
+ return;
+ }
+
+ if (this.HasTwoLines == false
+ || string.IsNullOrEmpty(this.Text))
{
this.textRun.Text = this.Text;
- this.textRun2.Text = "";
- string text = this.Text.Trim();
- if (this.HasTwoLines)
+ this.textRun2.Text = string.Empty;
+ return;
+ }
+
+ var text = this.Text.Trim();
+
+ // Find soft hyphen, break at its position and display a normal hyphen.
+ var hyphenIndex = text.IndexOf((char)173);
+
+ if (hyphenIndex >= 0)
+ {
+ this.textRun.Text = text.Substring(0, hyphenIndex) + "-";
+ this.textRun2.Text = text.Substring(hyphenIndex) + " ";
+ }
+ else
+ {
+ var centerIndex = this.Text.Length / 2;
+ // Find spaces nearest to center from left and right
+ var leftSpaceIndex = text.LastIndexOf(" ", centerIndex, centerIndex, StringComparison.CurrentCulture);
+ var rightSpaceIndex = text.IndexOf(" ", centerIndex, StringComparison.CurrentCulture);
+
+ if (leftSpaceIndex == -1
+ && rightSpaceIndex == -1)
+ {
+ this.textRun.Text = this.Text;
+ this.textRun2.Text = string.Empty;
+ }
+ else if (leftSpaceIndex == -1)
+ {
+ // Finds only space from right. New line adds on it
+ this.textRun.Text = text.Substring(0, rightSpaceIndex);
+ this.textRun2.Text = text.Substring(rightSpaceIndex) + " ";
+ }
+ else if (rightSpaceIndex == -1)
+ {
+ // Finds only space from left. New line adds on it
+ this.textRun.Text = text.Substring(0, leftSpaceIndex);
+ this.textRun2.Text = text.Substring(leftSpaceIndex) + " ";
+ }
+ else
{
- // Find soft hyphen, break at its position and display a normal hyphen.
- int hyphenIndex = text.IndexOf((char)173);
- if (hyphenIndex >= 0)
+ // Find nearest to center space and add new line on it
+ if (Math.Abs(centerIndex - leftSpaceIndex) < Math.Abs(centerIndex - rightSpaceIndex))
{
- this.textRun.Text = text.Substring(0, hyphenIndex) + "-";
- this.textRun2.Text = text.Substring(hyphenIndex) + " ";
+ this.textRun.Text = text.Substring(0, leftSpaceIndex);
+ this.textRun2.Text = text.Substring(leftSpaceIndex) + " ";
}
else
{
- int centerIndex = this.Text.Length / 2;
- // Find spaces nearest to center from left and right
- int leftSpaceIndex = text.LastIndexOf(" ", centerIndex, centerIndex);
- int rightSpaceIndex = text.IndexOf(" ", centerIndex, StringComparison.CurrentCulture);
- if ((leftSpaceIndex == -1) && (rightSpaceIndex == -1))
- {
- // The text can`t be separated. Add new line for glyph
- //textRun.Text += '\u0085';
- }
- else if (leftSpaceIndex == -1)
- {
- // Finds only space from right. New line adds on it
- this.textRun.Text = text.Substring(0, rightSpaceIndex);
- this.textRun2.Text = text.Substring(rightSpaceIndex) + " ";
- }
- else if (rightSpaceIndex == -1)
- {
- // Finds only space from left. New line adds on it
- this.textRun.Text = text.Substring(0, leftSpaceIndex);
- this.textRun2.Text = text.Substring(leftSpaceIndex) + " ";
- }
- else
- {
- // Find nearest to center space and add new line on it
- if (Math.Abs(centerIndex - leftSpaceIndex) < Math.Abs(centerIndex - rightSpaceIndex))
- {
- this.textRun.Text = text.Substring(0, leftSpaceIndex);
- this.textRun2.Text = text.Substring(leftSpaceIndex) + " ";
- }
- else
- {
- this.textRun.Text = text.Substring(0, rightSpaceIndex);
- this.textRun2.Text = text.Substring(rightSpaceIndex) + " ";
- }
- }
+ this.textRun.Text = text.Substring(0, rightSpaceIndex);
+ this.textRun2.Text = text.Substring(rightSpaceIndex) + " ";
}
}
}
@@ -223,4 +237,4 @@ void UpdateTextRun()
#endregion
}
-}
+}
\ No newline at end of file
diff --git a/Fluent.Ribbon/Converters/ApplicationMenuRightContentExtractorConverter.cs b/Fluent.Ribbon/Converters/ApplicationMenuRightScrollViewerExtractorConverter.cs
similarity index 88%
rename from Fluent.Ribbon/Converters/ApplicationMenuRightContentExtractorConverter.cs
rename to Fluent.Ribbon/Converters/ApplicationMenuRightScrollViewerExtractorConverter.cs
index ca0a7a817..2fa2f6833 100644
--- a/Fluent.Ribbon/Converters/ApplicationMenuRightContentExtractorConverter.cs
+++ b/Fluent.Ribbon/Converters/ApplicationMenuRightScrollViewerExtractorConverter.cs
@@ -2,13 +2,13 @@
{
using System;
using System.Globalization;
- using System.Windows.Controls;
+ using System.Windows;
using System.Windows.Data;
///
/// Extracts right content presenter of application menu converter
///
- public class ApplicationMenuRightContentExtractorConverter : IValueConverter
+ public class ApplicationMenuRightScrollViewerExtractorConverter : IValueConverter
{
#region Implementation of IValueConverter
@@ -24,7 +24,7 @@ public object Convert(object value, Type targetType, object parameter, CultureIn
var menu = value as ApplicationMenu;
if (menu != null)
{
- return menu.Template.FindName("PART_RightContentPresenter", menu) as ContentPresenter;
+ return menu.Template.FindName("PART_ScrollViewer", menu) as UIElement;
}
return value;
diff --git a/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj b/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj
index 95ca4e3e9..948f76797 100644
--- a/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj
+++ b/Fluent.Ribbon/Fluent.Ribbon.NET 4.0.csproj
@@ -53,7 +53,7 @@
- ..\packages\ControlzEx.2.0.0-dev025\lib\net40\ControlzEx.dll
+ ..\packages\ControlzEx.2.0.0-dev038\lib\net40\ControlzEx.dll
True
@@ -61,7 +61,7 @@
- ..\packages\ControlzEx.2.0.0-dev025\lib\net40\System.Windows.Interactivity.dll
+ ..\packages\ControlzEx.2.0.0-dev038\lib\net40\System.Windows.Interactivity.dll
True
@@ -89,12 +89,15 @@
+
+
+
-
+
@@ -135,7 +138,6 @@
-
@@ -208,6 +210,14 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
+
+ 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 688fcadc2..13a21801a 100644
--- a/Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj
+++ b/Fluent.Ribbon/Fluent.Ribbon.NET 4.5.csproj
@@ -53,7 +53,7 @@
- ..\packages\ControlzEx.2.0.0-dev025\lib\net45\ControlzEx.dll
+ ..\packages\ControlzEx.2.0.0-dev038\lib\net45\ControlzEx.dll
True
@@ -61,7 +61,7 @@
- ..\packages\ControlzEx.2.0.0-dev025\lib\net45\System.Windows.Interactivity.dll
+ ..\packages\ControlzEx.2.0.0-dev038\lib\net45\System.Windows.Interactivity.dll
True
@@ -89,12 +89,15 @@
+
+
+
-
+
@@ -135,7 +138,6 @@
-
@@ -208,6 +210,14 @@
MSBuild:Compile
Designer
+
+ Designer
+ MSBuild:Compile
+
+
+ Designer
+ MSBuild:Compile
+
MSBuild:Compile
Designer
diff --git a/Fluent.Ribbon/Helpers/PoupHelper.cs b/Fluent.Ribbon/Helpers/PoupHelper.cs
new file mode 100644
index 000000000..312f0cdfd
--- /dev/null
+++ b/Fluent.Ribbon/Helpers/PoupHelper.cs
@@ -0,0 +1,52 @@
+namespace Fluent.Helpers
+{
+ using System.Windows;
+ using System.Windows.Controls.Primitives;
+
+ ///
+ /// Helper class to position .
+ ///
+ public static class PopupHelper
+ {
+ ///
+ /// Positions like would but ignores the value of .
+ ///
+ public static CustomPopupPlacementCallback SimplePlacementCallback => GetSimplePlacement;
+
+ ///
+ /// Gets the values for a like would but ignores the value of .
+ ///
+ public static CustomPopupPlacement[] GetSimplePlacement(Size popupSize, Size targetSize, Point offset)
+ {
+ // Create placements which should never cover the target
+ return new[]
+ {
+ new CustomPopupPlacement
+ {
+ Point = new Point(0, 0),
+ PrimaryAxis = PopupPrimaryAxis.None
+ },
+ new CustomPopupPlacement
+ {
+ Point = new Point(-popupSize.Width, 0),
+ PrimaryAxis = PopupPrimaryAxis.Horizontal
+ },
+ new CustomPopupPlacement
+ {
+ Point = new Point(0, -popupSize.Height - targetSize.Height),
+ PrimaryAxis = PopupPrimaryAxis.Vertical
+ },
+ new CustomPopupPlacement
+ {
+ Point = new Point(-popupSize.Width, -popupSize.Height),
+ PrimaryAxis = PopupPrimaryAxis.Vertical
+ },
+ new CustomPopupPlacement
+ {
+ Point = new Point(targetSize.Width, -popupSize.Height),
+ PrimaryAxis = PopupPrimaryAxis.Horizontal
+ }
+ };
+ }
+ }
+}
\ No newline at end of file
diff --git a/Fluent.Ribbon/Internal/FocusWrapper.cs b/Fluent.Ribbon/Internal/FocusWrapper.cs
new file mode 100644
index 000000000..3538390e6
--- /dev/null
+++ b/Fluent.Ribbon/Internal/FocusWrapper.cs
@@ -0,0 +1,54 @@
+namespace Fluent.Internal
+{
+ using System;
+ using System.Windows;
+ using System.Windows.Input;
+
+ internal class FocusWrapper
+ {
+ private readonly IInputElement inputElement;
+ private readonly IntPtr handle;
+
+ private FocusWrapper(IInputElement inputElement)
+ {
+ this.inputElement = inputElement;
+ }
+
+ private FocusWrapper(IntPtr handle)
+ {
+ this.handle = handle;
+ }
+
+ public void Focus()
+ {
+ if (this.inputElement != null)
+ {
+ this.inputElement.Focus();
+ return;
+ }
+
+ if (this.handle != IntPtr.Zero)
+ {
+ NativeMethods.SetFocus(this.handle);
+ return;
+ }
+ }
+
+ public static FocusWrapper GetWrapperForCurrentFocus()
+ {
+ if (Keyboard.FocusedElement != null)
+ {
+ return new FocusWrapper(Keyboard.FocusedElement);
+ }
+
+ var handle = NativeMethods.GetFocus();
+
+ if (handle != IntPtr.Zero)
+ {
+ return new FocusWrapper(handle);
+ }
+
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/Fluent.Ribbon/Internal/KeyEventUtility.cs b/Fluent.Ribbon/Internal/KeyEventUtility.cs
new file mode 100644
index 000000000..e84e023c5
--- /dev/null
+++ b/Fluent.Ribbon/Internal/KeyEventUtility.cs
@@ -0,0 +1,34 @@
+namespace Fluent.Internal
+{
+ using System.Windows.Input;
+
+ internal static class KeyEventUtility
+ {
+ public static string GetStringFromKey(Key key)
+ {
+ var keyboardState = new byte[256];
+ if (NativeMethods.GetKeyboardState(keyboardState) == false)
+ {
+ return null;
+ }
+
+ var virtualKey = KeyInterop.VirtualKeyFromKey(key);
+ var scanCode = NativeMethods.MapVirtualKey((uint)virtualKey, NativeMethods.MapType.MAPVK_VK_TO_VSC);
+ var chars = new char[1];
+
+ var result = NativeMethods.ToUnicode((uint)virtualKey, scanCode, keyboardState, chars, chars.Length, 0);
+ switch (result)
+ {
+ case -1:
+ case 0:
+ return null;
+
+ case 1:
+ return chars[0].ToString();
+
+ default:
+ return null;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/Fluent.Ribbon/Internal/NativeMethods.cs b/Fluent.Ribbon/Internal/NativeMethods.cs
index 4d9236a61..b99c006f8 100644
--- a/Fluent.Ribbon/Internal/NativeMethods.cs
+++ b/Fluent.Ribbon/Internal/NativeMethods.cs
@@ -207,6 +207,12 @@ internal static void PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lP
[DllImport("user32.dll")]
internal static extern int SetWindowLong(IntPtr hWnd, GWL nIndex, WS dwNewLong);
+ [DllImport("user32.dll")]
+ internal static extern IntPtr GetFocus();
+
+ [DllImport("user32.dll")]
+ internal static extern IntPtr SetFocus(IntPtr hWnd);
+
/// Add and remove a native WindowStyle from the HWND.
/// A HWND for a window.
/// The styles to be removed. These can be bitwise combined.
@@ -230,6 +236,25 @@ public static bool _ModifyStyle(this IntPtr _hwnd, WS removeStyle, WS addStyle)
return true;
}
+ [DllImport("user32.dll", CharSet = CharSet.Unicode)]
+ internal static extern int ToUnicode(uint virtualKey, uint scanCode, byte[] keyStates, [MarshalAs(UnmanagedType.LPArray)] [Out] char[] chars, int charMaxCount, uint flags);
+
+ [DllImport("user32.dll")]
+ internal static extern bool GetKeyboardState(byte[] lpKeyState);
+
+ [DllImport("user32.dll")]
+ internal static extern uint MapVirtualKey(uint uCode, MapType uMapType);
+
+ // ReSharper disable InconsistentNaming
+ internal enum MapType : uint
+ {
+ MAPVK_VK_TO_VSC = 0x0,
+ MAPVK_VSC_TO_VK = 0x1,
+ MAPVK_VK_TO_CHAR = 0x2,
+ MAPVK_VSC_TO_VK_EX = 0x3,
+ }
+ // ReSharper restore InconsistentNaming
+
///
/// GetWindowLong values, GWL_*
///
diff --git a/Fluent.Ribbon/Internal/UIHelper.cs b/Fluent.Ribbon/Internal/UIHelper.cs
index 01ae4934e..cad9cbe28 100644
--- a/Fluent.Ribbon/Internal/UIHelper.cs
+++ b/Fluent.Ribbon/Internal/UIHelper.cs
@@ -60,6 +60,10 @@ public static TChildItem FindVisualChild(DependencyObject parent) wh
return null;
}
+ ///
+ /// Gets all visual children of .
+ ///
+ ///
public static IEnumerable GetVisualChildren(DependencyObject parent)
{
var visualChildrenCount = VisualTreeHelper.GetChildrenCount(parent);
@@ -74,5 +78,35 @@ public static IEnumerable GetVisualChildren(DependencyObject p
}
}
}
+
+ ///
+ /// Finds the parent control of type .
+ /// First looks at the visual tree and then at the logical tree to find the parent.
+ ///
+ /// The found visual/logical parent or null.
+ public static T GetParent(DependencyObject element)
+ where T : DependencyObject
+ {
+ var item = element;
+
+ while (item != null
+ && item is T == false)
+ {
+ item = VisualTreeHelper.GetParent(item);
+ }
+
+ if (item == null)
+ {
+ item = element;
+
+ while (item != null &&
+ item is T == false)
+ {
+ item = LogicalTreeHelper.GetParent(item);
+ }
+ }
+
+ return (T)item;
+ }
}
}
\ No newline at end of file
diff --git a/Fluent.Ribbon/Services/KeyTipService.cs b/Fluent.Ribbon/Services/KeyTipService.cs
index e1f7b428b..193187f37 100644
--- a/Fluent.Ribbon/Services/KeyTipService.cs
+++ b/Fluent.Ribbon/Services/KeyTipService.cs
@@ -24,8 +24,9 @@ internal class KeyTipService
// Is KeyTips Actived now
private KeyTipAdorner activeAdornerChain;
- // This element must be remembered to restore it
- IInputElement backUpFocusedElement;
+ // This element must be remembered to restore focus
+ private FocusWrapper backUpFocusedControl;
+
// Window where we attached
private Window window;
@@ -35,7 +36,6 @@ internal class KeyTipService
// Attached HWND source
private HwndSource attachedHwndSource;
- private static readonly KeyConverter keyConverter = new KeyConverter();
private string currentUserInput;
///
@@ -117,10 +117,7 @@ public void Attach()
// Hookup non client area messages
this.attachedHwndSource = (HwndSource)PresentationSource.FromVisual(this.window);
- if (this.attachedHwndSource != null)
- {
- this.attachedHwndSource.AddHook(this.WindowProc);
- }
+ this.attachedHwndSource?.AddHook(this.WindowProc);
}
///
@@ -146,12 +143,8 @@ public void Detach()
this.window = null;
}
- // Hookup non client area messages
- if (this.attachedHwndSource != null
- && this.attachedHwndSource.IsDisposed == false)
- {
- this.attachedHwndSource.RemoveHook(this.WindowProc);
- }
+ // Unhook non client area messages
+ this.attachedHwndSource?.RemoveHook(this.WindowProc);
}
// Window's messages hook up
@@ -177,13 +170,15 @@ private IntPtr WindowProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, re
private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
{
- if (e.IsRepeat)
+ if (e.IsRepeat
+ || e.Handled)
{
return;
}
if (this.ribbon.IsCollapsed
- || this.ribbon.IsEnabled == false)
+ || this.ribbon.IsEnabled == false
+ || this.window.IsActive == false)
{
return;
}
@@ -195,7 +190,6 @@ private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
&& e.SystemKey <= Key.NumPad9)
{
this.activeAdornerChain?.Terminate();
- this.ClearUserInput();
return;
}
@@ -207,19 +201,10 @@ private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
{
this.ShowDelayed();
}
- else if (this.activeAdornerChain != null
- && this.activeAdornerChain.IsAdornerChainAlive)
- {
- // Focus ribbon
- this.backUpFocusedElement = Keyboard.FocusedElement;
- this.ribbon.Focusable = true;
- //this.ribbon.Focus();
-
- this.activeAdornerChain.Terminate();
- }
else
{
- this.ClearUserInput();
+ this.activeAdornerChain?.Terminate();
+ return;
}
}
else if (e.Key == Key.Escape
@@ -228,6 +213,7 @@ private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
this.activeAdornerChain.ActiveKeyTipAdorner.Back();
this.ClearUserInput();
e.Handled = true;
+ return;
}
else
{
@@ -238,54 +224,70 @@ private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
return;
}
- Key actualKey = e.Key == Key.System ? e.SystemKey : e.Key;
- bool isLetterKey = ((actualKey >= Key.A && actualKey <= Key.Z) || (actualKey >= Key.D0 && actualKey <= Key.D9) || (actualKey >= Key.NumPad0 && actualKey <= Key.NumPad9));
+ var actualKey = e.Key == Key.System ? e.SystemKey : e.Key;
+ // we need to get the real string input for the key because of keys like ä,ö,ü #258
+ var key = KeyEventUtility.GetStringFromKey(actualKey);
+ var isKeyRealInput = string.IsNullOrEmpty(key) == false;
- if (isLetterKey)
+ // Don't do anything and let WPF handle the rest
+ if (isKeyRealInput == false)
{
- // Should we show the keytips and immediately react to key?
- if (this.activeAdornerChain == null
- || this.activeAdornerChain.IsAdornerChainAlive == false
- || this.activeAdornerChain.AreAnyKeyTipsVisible == false)
+ // This block is a "temporary" fix for keyboard navigation not matching the office behavior.
+ // If someone finds a way to implement it properly, here is your starting point.
+ // In office: If you navigate by keyboard (in menus) and keytips are shown they are shown or hidden based on the menu you are in.
+ // Implementing navigation the way office does would require complex focus/state tracking etc. so i decided to just terminate keytips and not restore focus.
{
- this.ShowImmediatly();
+ this.backUpFocusedControl = null;
+ this.activeAdornerChain?.Terminate();
}
+ return;
}
- if (this.activeAdornerChain == null)
+ var shownImmediately = false;
+
+ // Should we show the keytips and immediately react to key?
+ if (this.activeAdornerChain == null
+ || this.activeAdornerChain.IsAdornerChainAlive == false
+ || this.activeAdornerChain.AreAnyKeyTipsVisible == false)
{
- return;
+ this.ShowImmediatly();
+ shownImmediately = true;
}
- string previousInput = this.currentUserInput;
-
- if (isLetterKey)
+ if (this.activeAdornerChain == null)
{
- this.currentUserInput += keyConverter.ConvertToString(actualKey);
+ return;
}
- // If no key tips match the current input, continue with the previously entered and still correct keys.
- if (!isLetterKey || this.activeAdornerChain.ActiveKeyTipAdorner.ContainsKeyTipStartingWith(this.currentUserInput) == false)
+ var previousInput = this.currentUserInput;
+ this.currentUserInput += key;
+
+ if (this.activeAdornerChain.ActiveKeyTipAdorner.ContainsKeyTipStartingWith(this.currentUserInput) == false)
{
- MenuItem item = Keyboard.FocusedElement as MenuItem;
- if (item != null && !isLetterKey)
+ // Handles access-keys #258
+ if (shownImmediately)
{
- item.HandleKeyDown(e);
+ this.activeAdornerChain?.Terminate();
return;
}
+ // If no key tips match the current input, continue with the previously entered and still correct keys.
this.currentUserInput = previousInput;
System.Media.SystemSounds.Beep.Play();
+ e.Handled = true;
+ return;
}
else if (this.activeAdornerChain.ActiveKeyTipAdorner.Forward(this.currentUserInput, true))
{
this.ClearUserInput();
e.Handled = true;
+ return;
}
else
{
this.activeAdornerChain.ActiveKeyTipAdorner.FilterKeyTips(this.currentUserInput);
e.Handled = true;
+ return;
}
}
}
@@ -293,8 +295,10 @@ private void OnWindowPreviewKeyDown(object sender, KeyEventArgs e)
private void OnWindowKeyUp(object sender, KeyEventArgs e)
{
if (this.ribbon.IsCollapsed
- || this.ribbon.IsEnabled == false)
+ || this.ribbon.IsEnabled == false
+ || this.window.IsActive == false)
{
+ this.activeAdornerChain?.Terminate();
return;
}
@@ -331,19 +335,15 @@ private void ClearUserInput()
private void RestoreFocus()
{
- if (this.backUpFocusedElement != null)
- {
- this.backUpFocusedElement.Focus();
- this.backUpFocusedElement = null; // Release the reference, so GC can work
- }
-
- this.ribbon.Focusable = false;
+ this.backUpFocusedControl?.Focus();
+ this.backUpFocusedControl = null;
}
private void OnAdornerChainTerminated(object sender, EventArgs e)
{
this.activeAdornerChain.Terminated -= this.OnAdornerChainTerminated;
this.activeAdornerChain = null;
+ this.ClearUserInput();
this.RestoreFocus();
}
@@ -359,28 +359,20 @@ private void OnDelayedShow(object sender, EventArgs e)
private void ShowImmediatly()
{
- this.timer.Stop();
- this.backUpFocusedElement = Keyboard.FocusedElement;
-
- // Focus ribbon
- this.ribbon.Focusable = true;
- //this.ribbon.Focus();
-
this.Show();
}
private void ShowDelayed()
{
- if (this.activeAdornerChain != null)
- {
- this.activeAdornerChain.Terminate();
- }
+ this.activeAdornerChain?.Terminate();
this.timer.Start();
}
private void Show()
{
+ this.timer.Stop();
+
// Check whether the window is
// - still present (prevents exceptions when window is closed by system commands)
// - still active (prevents keytips showing during Alt-Tab'ing)
@@ -391,6 +383,11 @@ private void Show()
return;
}
+ this.backUpFocusedControl = FocusWrapper.GetWrapperForCurrentFocus();
+
+ // Focus ribbon
+ this.ribbon.Focus();
+
this.ClearUserInput();
this.activeAdornerChain = new KeyTipAdorner(this.ribbon, this.ribbon, null);
@@ -398,7 +395,8 @@ private void Show()
// Special behavior for backstage
var specialControl = this.GetBackstage()
- ?? (DependencyObject)this.GetApplicationMenu();
+ ?? this.GetApplicationMenu()
+ ?? this.GetStartScreen();
if (specialControl != null)
{
@@ -410,14 +408,14 @@ private void Show()
}
}
- private Backstage GetBackstage()
+ private DependencyObject GetBackstage()
{
if (this.ribbon.Menu == null)
{
return null;
}
- var control = this.ribbon.Menu as Backstage ?? UIHelper.FindImmediateVisualChild(this.ribbon.Menu, obj => obj.Visibility == Visibility.Visible && obj.IsOpen);
+ var control = this.ribbon.Menu as Backstage ?? UIHelper.FindImmediateVisualChild(this.ribbon.Menu, obj => obj.Visibility == Visibility.Visible);
if (control == null)
{
@@ -429,7 +427,7 @@ private Backstage GetBackstage()
: null;
}
- private ApplicationMenu GetApplicationMenu()
+ private DependencyObject GetApplicationMenu()
{
if (this.ribbon.Menu == null)
{
@@ -448,12 +446,27 @@ private ApplicationMenu GetApplicationMenu()
: null;
}
+ private DependencyObject GetStartScreen()
+ {
+ var control = this.ribbon.StartScreen;
+
+ if (control == null)
+ {
+ return null;
+ }
+
+ return control.IsOpen
+ ? control
+ : null;
+ }
+
private void DirectlyForwardToSpecialControl(DependencyObject specialControl)
{
var keys = KeyTip.GetKeys(specialControl);
+
if (string.IsNullOrEmpty(keys) == false)
{
- this.activeAdornerChain.Forward(KeyTip.GetKeys(specialControl), false);
+ this.activeAdornerChain.Forward(keys, false);
}
else
{
diff --git a/Fluent.Ribbon/Themes/Generic/Controls/Button.xaml b/Fluent.Ribbon/Themes/Generic/Controls/Button.xaml
new file mode 100644
index 000000000..c90bf739d
--- /dev/null
+++ b/Fluent.Ribbon/Themes/Generic/Controls/Button.xaml
@@ -0,0 +1,61 @@
+
+
+
+
\ No newline at end of file
diff --git a/Fluent.Ribbon/Themes/Generic/Controls/TwoLineLabel.xaml b/Fluent.Ribbon/Themes/Generic/Controls/TwoLineLabel.xaml
index faa777864..8bac5f479 100644
--- a/Fluent.Ribbon/Themes/Generic/Controls/TwoLineLabel.xaml
+++ b/Fluent.Ribbon/Themes/Generic/Controls/TwoLineLabel.xaml
@@ -17,6 +17,7 @@
TextAlignment="Center"
HorizontalAlignment="Center"
VerticalAlignment="Center" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenu.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenu.xaml
index be754595f..9d7669b5e 100644
--- a/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenu.xaml
+++ b/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenu.xaml
@@ -1,6 +1,7 @@

@@ -90,8 +91,10 @@
-
@@ -129,25 +131,15 @@
MinWidth="100" />
-
-
-
-
-
-
-
-
diff --git a/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenuItem.xaml b/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenuItem.xaml
index dd102253e..fa3a9a0ea 100644
--- a/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenuItem.xaml
+++ b/Fluent.Ribbon/Themes/Office2010/Controls/ApplicationMenuItem.xaml
@@ -3,9 +3,10 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:Fluent="clr-namespace:Fluent"
+ xmlns:FluentHelpers="clr-namespace:Fluent.Helpers"
xmlns:Converters="clr-namespace:Fluent.Converters"
mc:Ignorable="d">
-
+
@@ -892,7 +893,7 @@
VerticalAlignment="Center"
Grid.Column="2"
d:LayoutOverrides="Width"
- TextWrapping="NoWrap" />
+ TextWrapping="NoWrap" />
@@ -71,7 +71,7 @@
-
+
-
+
@@ -694,20 +616,8 @@
TargetType="{x:Type Fluent:RibbonWindow}">
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
@@ -746,14 +645,12 @@
Value="True" />
+ Value="0 57 0 0" />
-
diff --git a/Fluent.Ribbon/Themes/Office2013/Controls/ApplicationMenu.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/ApplicationMenu.xaml
index bfe1de7d2..5d8d6471b 100644
--- a/Fluent.Ribbon/Themes/Office2013/Controls/ApplicationMenu.xaml
+++ b/Fluent.Ribbon/Themes/Office2013/Controls/ApplicationMenu.xaml
@@ -1,6 +1,7 @@

@@ -30,8 +31,10 @@
-
@@ -68,25 +70,15 @@
MinWidth="100" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabControl.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabControl.xaml
index a19d5717d..c8fa59525 100644
--- a/Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabControl.xaml
+++ b/Fluent.Ribbon/Themes/Office2013/Controls/BackstageTabControl.xaml
@@ -245,9 +245,9 @@
-
-
@@ -260,19 +260,19 @@
-
-
-
+
-
+
@@ -287,8 +287,8 @@
+ Value="{Binding ParentBackstage.Background, RelativeSource={RelativeSource Self}, FallbackValue=Red}" />
+ Value="{Binding ParentBackstage.Background, RelativeSource={RelativeSource Self}, FallbackValue=Red}" />
\ No newline at end of file
diff --git a/Fluent.Ribbon/Themes/Office2013/Controls/Button.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/Button.xaml
index 69110ed1b..d3d88f03d 100644
--- a/Fluent.Ribbon/Themes/Office2013/Controls/Button.xaml
+++ b/Fluent.Ribbon/Themes/Office2013/Controls/Button.xaml
@@ -13,30 +13,28 @@
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
- Height="Auto"
- HorizontalAlignment="Left"
- VerticalAlignment="Stretch">
-
-
-
-
-
-
+ HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
+ VerticalAlignment="{TemplateBinding VerticalAlignment}"
+ Height="Auto">
+
+
+
+
-
-
+
\ No newline at end of file
diff --git a/Fluent.Ribbon/Themes/Office2013/Controls/InRibbonGallery.xaml b/Fluent.Ribbon/Themes/Office2013/Controls/InRibbonGallery.xaml
index 7b1faf9b6..6de6f1405 100644
--- a/Fluent.Ribbon/Themes/Office2013/Controls/InRibbonGallery.xaml
+++ b/Fluent.Ribbon/Themes/Office2013/Controls/InRibbonGallery.xaml
@@ -1,6 +1,7 @@

@@ -405,7 +406,8 @@
CanAddToQuickAccessToolBar="False"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource = {RelativeSource TemplatedParent}}" />
+ Visibility="{TemplateBinding CanMinimize, Converter={StaticResource boolToVisibilityConverter}}" />
-
diff --git a/Fluent.Ribbon/Themes/Office2013/Generic.txt b/Fluent.Ribbon/Themes/Office2013/Generic.txt
index 0715f4444..7b21250bd 100644
--- a/Fluent.Ribbon/Themes/Office2013/Generic.txt
+++ b/Fluent.Ribbon/Themes/Office2013/Generic.txt
@@ -1,3 +1,5 @@
+Generic\Controls\Button.xaml
+Generic\Controls\WindowCommands.xaml
Office2013\Colors\Colors.xaml
Office2013\Colors\ColorsWhite.xaml
Office2013\Images\Images.xaml
diff --git a/Fluent.Ribbon/Themes/Office2013/RibbonWindow.xaml b/Fluent.Ribbon/Themes/Office2013/RibbonWindow.xaml
index 07bedc7a2..82f11ce02 100644
--- a/Fluent.Ribbon/Themes/Office2013/RibbonWindow.xaml
+++ b/Fluent.Ribbon/Themes/Office2013/RibbonWindow.xaml
@@ -10,59 +10,51 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -77,11 +69,8 @@
-
+ TargetName="Adorner"
+ Value="0" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
diff --git a/Fluent.Ribbon/Themes/Windows8/Controls/Button.xaml b/Fluent.Ribbon/Themes/Windows8/Controls/Button.xaml
index 0a3af38d9..d6768402a 100644
--- a/Fluent.Ribbon/Themes/Windows8/Controls/Button.xaml
+++ b/Fluent.Ribbon/Themes/Windows8/Controls/Button.xaml
@@ -13,30 +13,28 @@
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
- Height="Auto"
- HorizontalAlignment="Left"
- VerticalAlignment="Stretch">
-
-
-
-
-
-
+ HorizontalAlignment="{TemplateBinding HorizontalAlignment}"
+ VerticalAlignment="{TemplateBinding VerticalAlignment}"
+ Height="Auto">
+
+
+
+
@@ -421,7 +422,8 @@
CanAddToQuickAccessToolBar="False"
IsChecked="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource = {RelativeSource TemplatedParent}}" />
-
+
+
+
+
+
+
+ Visibility="{TemplateBinding CanMinimize, Converter={StaticResource boolToVisibilityConverter}}" />
diff --git a/Fluent.Ribbon/Themes/Windows8/Controls/RibbonTabItem.xaml b/Fluent.Ribbon/Themes/Windows8/Controls/RibbonTabItem.xaml
index cd93cd492..124213a1d 100644
--- a/Fluent.Ribbon/Themes/Windows8/Controls/RibbonTabItem.xaml
+++ b/Fluent.Ribbon/Themes/Windows8/Controls/RibbonTabItem.xaml
@@ -224,11 +224,11 @@
Padding="15,0,0,0"
Grid.ColumnSpan="1">
-
diff --git a/Fluent.Ribbon/Themes/Windows8/Generic.txt b/Fluent.Ribbon/Themes/Windows8/Generic.txt
index 06450a471..d707c2e57 100644
--- a/Fluent.Ribbon/Themes/Windows8/Generic.txt
+++ b/Fluent.Ribbon/Themes/Windows8/Generic.txt
@@ -1,3 +1,5 @@
+Generic\Controls\Button.xaml
+Generic\Controls\WindowCommands.xaml
Office2010\Colors\Colors.xaml
Windows8\Colors\Colors.xaml
Windows8\Colors\ColorsSilver.xaml
diff --git a/Fluent.Ribbon/Themes/Windows8/RibbonWindow.xaml b/Fluent.Ribbon/Themes/Windows8/RibbonWindow.xaml
index d7e748ad3..d3000d879 100644
--- a/Fluent.Ribbon/Themes/Windows8/RibbonWindow.xaml
+++ b/Fluent.Ribbon/Themes/Windows8/RibbonWindow.xaml
@@ -9,18 +9,6 @@
xmlns:Converters="clr-namespace:Fluent.Converters">
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ TargetName="PART_Icon"
+ Value="0" />
-
-
+ TargetName="PART_Border"
+ Value="Collapsed" />
-
-
-
-
-
-
-
-
-
+ TargetName="WindowResizeGrip"
+ Value="Collapsed" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-