简体   繁体   中英

Change background color of the visible part of a RibbonGroup when it is collapsed

I'm using MS Ribbon control in a C# WPF application. This control has several RibbonGroups . One of these has RibbonButtons which can change their background color when a certain event occurs.

As long as this RibbonGroup is not collapsed, the colored RibbonButtons are visible and user can take notice of the changed color. But if app window gets smaller and my RibbonGroup is collapsed, the colored RibbonButtons are out of the view.

I tried to change the background color of the RibbonGroup , but this value is set to both parts - visible and invisible - of the collapsed RibbonGroup .

Setting background color of the RibbonGroup.Header colorises only the TextBlock with title and moreover this action makes the down-arrow invisible when RibbonGroup is collapsed.

This is what I'm aiming at:

在此处输入图像描述

Any ideas are appreciated!

--------- UPDATE -------------

My current implementation looks like this. I used Bindings to set background colors of the Buttons and a Multibinding to set background of the RibbonGroup and to respond to changes of IsCollapsed and IsDropDownOpen properties.

The problem of this approach is - I have to use the "right" color at the "right" moment: transparent when the group is not collapsed, light gray when menu is dropped down and so on.

...

xmlns:converters="clr-namespace:ControlFunctions.Converters"

...

<UserControl.Resources>
    <ResourceDictionary>
        <SolidColorBrush x:Key="RibbonBackground" Color="#f0f0f0" />
        <converters:ButtonBackgroundToGroupBackgroundConverter x:Key="ButtonBackgroundToGroupBackgroundConverter" />
    </ResourceDictionary>
</UserControl.Resources>
        
<Ribbon>
    <RibbonTab Header="Home">
        <RibbonGroup x:Name="_functionGroup" Header="Functions">
            <RibbonGroup.Background>
                    <MultiBinding Converter="{StaticResource ButtonBackgroundToGroupBackgroundConverter}" FallbackValue="{StaticResource RibbonBackground}" >
                            <Binding ElementName="_functionGroup" Path="IsCollapsed" />
                            <Binding ElementName="_functionGroup" Path="IsDropDownOpen" />
                            <Binding Path="Background_Button1" />
                            <Binding Path="Background_Button2" />
                            <Binding Path="Background_Button3" />
                    </MultiBinding>
            </RibbonGroup.Background>           
        
            <RibbonButton Label="Button 1" Background="{Binding Path=Background_Button1}" />
            <RibbonButton Label="Button 2" Background="{Binding Path=Background_Button2}" />
            <RibbonButton Label="Button 3" Background="{Binding Path=Background_Button3}" />
        </RibbonGroup>
    </RibbonTab>
</Ribbon>

Converters.cs

public class ButtonBackgroundToGroupBackgroundConverter : IMultiValueConverter
{
    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        //no value set yet
        if (values[0] == DependencyProperty.UnsetValue || values[0] == null || values[1] == DependencyProperty.UnsetValue || values[1] == null) return Binding.DoNothing;
        
        if ((bool)values[0] == false) return null; //the group is not collapsed -> no background color, leave it transparent
        if ((bool)values[1]) return DependencyProperty.UnsetValue; //the group is collapsed AND menu is dropped down -> set Ribbon background color (=FallbackValue)

        for (int i = 2; i < values.Length; i++) if (values[i] != null) return values[i]; //one of the buttons is colored -> use its color for the group
        
        return null; //none of the buttons is colored -> no background color for the group, leave it transparent
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

My solution isn't pretty, but it does work.

<!--A ribbon with SizeChanged event-->
<Ribbon DockPanel.Dock="Top" SizeChanged="Ribbon_SizeChanged">
    <RibbonTab Header="One">
        <!--A couple ribbon groups to fill up space-->
        <RibbonGroup Header="One">
            <RibbonButton Label="Button Number One"/>
        </RibbonGroup>
        <RibbonGroup Header="Two">
            <RibbonButton Label="Button Number Two"/>
        </RibbonGroup>
        
        <!--The ribbon group we want to change the color of, in this case named "Group"-->
        <RibbonGroup Header="Three" Name="Group">
            <RibbonButton Label="Button Number Three"/>
        </RibbonGroup>
    </RibbonTab>
</Ribbon>
private void Ribbon_SizeChanged(object sender, SizeChangedEventArgs e)
{
    if (Group.IsCollapsed && IWantToChangeRibbonGroupColor)
    {
        //Find the RibbonToggleButton inside the ribbon group
        var button = FindVisualChild<RibbonToggleButton>(Group);
        button.Background = Brushes.Green;
    }
}

//A common helper method I use for finding element children
public static ChildType FindVisualChild<ChildType>(DependencyObject obj) where ChildType : DependencyObject
{
    int num = VisualTreeHelper.GetChildrenCount(obj) - 1;
    for (int i = 0; i <= num; i++)
    {
        DependencyObject child = VisualTreeHelper.GetChild(obj, i);
        if (child != null && child is ChildType)
        {
            return (ChildType)child;
        }

        child = FindVisualChild<ChildType>(child);
        if (child != null)
        {
            return (ChildType)child;
        }
    }

    return null;
}

This could be wrapped up into a neat little attached behavior , but I don't feel like going through that effort at the moment.

There isn't a property I know of that will let you change what you want, but there's nothing stopping you from digging through the visual tree and changing the background color manually. Using the visual tree debugging tools in Visual Studio, you can see what elements make up the collapsed RibbonGroup .

功能区视觉树

In this case, it looks like the best interior element to change the color of would be the RibbonToggleButton .

The aim of the code is to find out when the RibbonGroup collapses, get a reference to the RibbonToggleButton inside it, and then set Background .

Unfortunately, there is no event I could find for when a RibbonGroup switches in or out of its collapsed state. But at least there is a property: RibbonGroup.IsCollapsed . I'm reasonably assuming that IsCollapsed will only change when the size of the overall Ribbon changes, so I chose to check IsCollapsed inside of Ribbon.SizeChanged . (Note: I tried using RibbonGroup.SizeChanged first, but this did not work correctly. The RibbonGroup would sometimes revert to its original color.)

In the example code I gave, I got a reference to the RibbonGroup I wanted to use by giving that RibbonGroup a name, but as mentioned you could implement it other ways, such as by designing an attached behavior . Once I have the RibbonGroup I loop through all the child elements, looking for that RibbonToggleButton . When I find it, I set the background. This should continue to work so long as the ControlTemplate for RibbonGroup remains unchanged.

Depending on your implementation of IWantToChangeRibbonGroupColor , you'll probably also want to run the color changing method when the value of IWantToChangeRibbonGroupColor changes. So that the color will change even when the size of the ribbon doesn't.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM