WPF Ribbon - hiding tab header (single tab application)
I managed to hide both the tab headers and the application menu by shifting the control 47 pixels upwards...
<r:Ribbon Margin="0,-47,0,0" DockPanel.Dock="Top" x:Name="ribbon">
Note: you can hide just the application menu and not the tabs by doing this...
<r:Ribbon DockPanel.Dock="Top" x:Name="ribbon">
<r:Ribbon.ApplicationMenu>
<r:RibbonApplicationMenu Visibility="Collapsed" />
</r:Ribbon.ApplicationMenu>
Hiding just the tab headers, I can't quite do. I did get pretty close by overriding the ribbon class as follows...
class RibbonNoTab : Ribbon
{
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
var ctrl = this.GetDescendants<Grid>().FirstOrDefault();
if (ctrl != null)
{
ctrl.RowDefinitions[1].Height = new GridLength(0, System.Windows.GridUnitType.Pixel);
}
}
}
The GetDescendants extension method just searches the visual tree for something of a specified type. It was taken from here: http://blog.falafel.com/finding-controls-by-type-in-silverlight-and-wpf/
The only issue with the above method was that there looks like a 1 pixel high bar remaining. You have to look pretty closely to see it!
Piggybacking off the other answer, there are a few ways you can do it without using a custom derived class
public class RibbonBehavior
{
public static bool GetHideRibbonTabs(DependencyObject obj)
{
return (bool)obj.GetValue(HideRibbonTabsProperty);
}
public static void SetHideRibbonTabs(DependencyObject obj, bool value)
{
obj.SetValue(HideRibbonTabsProperty, value);
}
// Using a DependencyProperty as the backing store for HideRibbonTabs. This enables animation, styling, binding, etc...
public static readonly DependencyProperty HideRibbonTabsProperty =
DependencyProperty.RegisterAttached("HideRibbonTabs", typeof(bool), typeof(RibbonBehavior), new UIPropertyMetadata(false,OnHideRibbonTabsChanged));
public static void OnHideRibbonTabsChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d == null || d.GetType() != typeof(Ribbon)) return;
(d as Ribbon).Loaded += ctrl_Loaded;
}
static void ctrl_Loaded(object sender, RoutedEventArgs e)
{
if (sender == null || sender.GetType() != typeof(Ribbon)) return;
Ribbon _ribbon = (Ribbon)sender;
var tabGrid = _ribbon.GetDescendants<Grid>().FirstOrDefault();
tabGrid.RowDefinitions[1].Height = new GridLength(0, System.Windows.GridUnitType.Pixel);
foreach (Line line in _ribbon.GetDescendants<Line>())
line.Visibility = Visibility.Collapsed;
}
}
then in your xaml:
<Ribbon SelectedIndex="0" a:RibbonBehavior.HideRibbonTabs="true">
Which will give you a nice square ribbon box with no tab:
Leaving out the code collapsing the lines leaves a little blip where the tab used to be, which was bothering me.
You could also put that loaded code straight into the code behind if you're not using MVVM, or in an EventToCommand if you are. This way is less reusable, but it's the same results.
EDIT: Here's the code for the GetDescendant methods
public static class VisualTreeExtensions
{
/// <summary>
/// Gets children, children’s children, etc. from
/// the visual tree that match the specified type
/// </summary>
public static List<T> GetDescendants<T>(this DependencyObject parent)
where T : UIElement
{
List<T> children = new List<T>();
int count = VisualTreeHelper.GetChildrenCount(parent);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
if (child is T)
{
children.Add((T)child);
}
children.AddRange(child.GetDescendants<T>());
}
return children;
}
else
{
return new List<T> { };
}
}
/// <summary>
/// Gets children, children’s children, etc. from
/// the visual tree that match the specified type and elementName
/// </summary>
public static List<T> GetDescendants<T>(this DependencyObject parent, string elementName)
where T : UIElement
{
List<T> children = new List<T>();
int count = VisualTreeHelper.GetChildrenCount(parent);
if (count > 0)
{
for (int i = 0; i < count; i++)
{
UIElement child = (UIElement)VisualTreeHelper.GetChild(parent, i);
if (child is T && (child is FrameworkElement)
&& (child as FrameworkElement).Name == elementName)
{
children.Add((T)child);
}
children.AddRange(child.GetDescendants<T>(elementName));
}
return children;
}
else
{
return new List<T> { };
}
}
/// <summary>
/// Gets the first child, child’s child, etc.
/// from the visual tree that matches the specified type
/// </summary>
public static T GetDescendant<T>(this DependencyObject parent)
where T : UIElement
{
List<T> descendants = parent.GetDescendants<T>();
if (descendants.Count > 0)
{
return descendants[0];
}
else
{
return null;
}
}
/// <summary>
/// Gets the first child, child’s child, etc. from
/// the visual tree that matches the specified type and elementName
/// </summary>
public static T GetDescendant<T>(this DependencyObject parent, string elementName)
where T : UIElement
{
List<T> descendants = parent.GetDescendants<T>(elementName);
if (descendants.Count > 0)
{
return descendants[0];
}
else
{
return null;
}
}
/// <summary>
/// Gets the first parent, parent’s parent, etc. from the
/// visual tree that matches the specified type
/// </summary>
public static T GetAntecedent<T>(this DependencyObject root)
where T : UIElement
{
if (root == null)
{
return null;
}
if (root is T)
{
return (T)root;
}
else
{
DependencyObject parent = VisualTreeHelper.GetParent(root);
if (parent == null)
{
return null;
}
else
{
return parent.GetAntecedent<T>();
}
}
}
/// <summary>
/// Gets the first parent, parent’s parent, etc. from the
/// visual tree that matches the specified type and elementName
/// </summary>
public static T GetAntecedent<T>(this DependencyObject root, string elementName)
where T : UIElement
{
if (root == null)
{
return null;
}
if (root is T && (root is FrameworkElement)
&& (root as FrameworkElement).Name == elementName)
{
return (T)root;
}
else
{
DependencyObject parent = VisualTreeHelper.GetParent(root);
if (parent == null)
{
return null;
}
else
{
return parent.GetAntecedent<T>(elementName);
}
}
}
}