Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

WPF ToolBar - Detect when item is set into ToolBarOverflowPanel

Tags:

wpf

I am aware of the IsOverflowOpen and HasOverflowItems properties but I am looking for a way to tell whether the item (button, radiobutton...) has moved into the ToolBarOverflowPanel so I can use a trigger to change its style.

I need this to be able to reproduce some UWP ToolBar styles (Windows 10 Mail, Word, Excel...). I have successfully reproduced most of the style and the only missing bit is to be able to changed the style of my item when it is in the overflow panel.

On the screenshot of what I am trying to reproduce, you can clearly see that the Special Ident and Line Spacing buttons have changed style based on whether they are displayed or overflowed. Windows 10 ToolBar Style Screenshot

like image 511
Amaury Levé Avatar asked Mar 31 '16 08:03

Amaury Levé


1 Answers

You can't do it with xaml only. You have to either use the code behind or create some attached properties.

Here is the solution with the AttachedProperty:

First you need to create an helper class exposing 2 properties:

  • The IsInOverflowPanel read-only property that you will use to trigger the style change.
  • The TrackParentPanel property, which is the enable/disable mechanism.

Here is the implementation:

public static class ToolBarHelper
{
    public static readonly DependencyPropertyKey IsInOverflowPanelKey =
        DependencyProperty.RegisterAttachedReadOnly("IsInOverflowPanel", typeof(bool), typeof(ToolBarHelper), new PropertyMetadata(false));

    public static readonly DependencyProperty IsInOverflowPanelProperty = IsInOverflowPanelKey.DependencyProperty;

    [AttachedPropertyBrowsableForType(typeof(UIElement))]
    public static bool GetIsInOverflowPanel(UIElement target)
    {
        return (bool)target.GetValue(IsInOverflowPanelProperty);
    }

    public static readonly DependencyProperty TrackParentPanelProperty =
        DependencyProperty.RegisterAttached("TrackParentPanel", typeof(bool), typeof(ToolBarHelper),
                                             new PropertyMetadata(false, OnTrackParentPanelPropertyChanged));

    public static void SetTrackParentPanel(DependencyObject d, bool value)
    {
        d.SetValue(TrackParentPanelProperty, value);
    }

    public static bool GetTrackParentPanel(DependencyObject d)
    {
        return (bool)d.GetValue(TrackParentPanelProperty);
    }

    private static void OnTrackParentPanelPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var element = d as UIElement;
        if (element != null)
        {
            bool newValue = (bool)e.NewValue;
            if (newValue)
            {
                element.LayoutUpdated += (s, arg) => OnControlLayoutUpdated(element);
            }
        }
    }
    private static void OnControlLayoutUpdated(UIElement element)
    {
        var isInOverflow = TreeHelper.FindParent<ToolBarOverflowPanel>(element) != null;
        element.SetValue(IsInOverflowPanelKey, isInOverflow);
    }
}

public static class TreeHelper
{
    public static T FindParent<T>(this DependencyObject obj) where T : DependencyObject
    {
        return obj.GetAncestors().OfType<T>().FirstOrDefault();
    }

    public static IEnumerable<DependencyObject> GetAncestors(this DependencyObject element)
    {
        do
        {
            yield return element;
            element = VisualTreeHelper.GetParent(element);
        } while (element != null);
    }
}

Then, for every items which need to change style do the following:

<Button x:Name="DeleteButton" Content="Delete" helpers:ToolBarHelper.TrackParentPanel="True">
    <Button.Style>
        <Style BasedOn="{StaticResource {x:Static ToolBar.ButtonStyleKey}}" TargetType="{x:Type Button}">
            <Style.Triggers>
                <Trigger Property="helpers:ToolBarHelper.IsInOverflowPanel" Value="True">
                    <!-- The Overflow style setters -->
                </Trigger>
            </Style.Triggers>
        </Style>
    </Button.Style>
</Button>
like image 167
Amaury Levé Avatar answered Oct 04 '22 22:10

Amaury Levé