WPF RibbonWindow doesn't show Grip to resize window

2.1k Views Asked by At

I have a RibbonWindow where my WindowStyle is set to None, so what I can't understand is what have happened to the Grip to resize the window?! Even if my controls have their Margin set to 0 in the Bottom part of them will be hidden... It's a strange behaviour.

But if I change the bottom Margin of the controls it's ok, but the Grip can't be seen anyway, probably because part of the client area is hidden...

I have to say, if a have a WPF Window, this doesn't happen, it only happens with the RibbonWindow. And I am using the RibbonWindow because the Ribbon has other look in the proper window.

So what can I do to solve the problem with the Grip?

Some of my code...

<rib:RibbonWindow x:Class="MyApp.Views.MainView"
                  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                  xmlns:rib="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
                  AllowsTransparency="True"
                  Background="Transparent"
                  Height="750"
                  ResizeMode="CanResizeWithGrip"
                  Width="1000"
                  WindowStartupLocation="CenterScreen"
                  WindowStyle="None">

    <Grid Margin="0, 0, 0, 20">
        <Border Background="Black"
                CornerRadius="5"
                Opacity="0.5"/>
    </Grid>
</rib:RibbonWindow>

Thanks in advance!

1

There are 1 best solutions below

0
On BEST ANSWER

This was intriguing to debug. Turns out that the style for the window has a bug: if the system is defined to have IsGlassEnabled == true (in Win7 Aero theme makes it true) then the window relies on the Microsoft.Windows.Shell.WindowChrome (from Microsoft.Windows.Shell assembly) to draw the border and the top buttons of the window; and this WindowChrome has its GlassFrameThickness property set to 8,30,8,8 in combination with NonClientFrameEdges set to Bottom.

What happens is that because of AllowsTransparency == true the glass border is transparent but the window still "cuts" its thickness from the overall window size because the WindowChrome defines NonClientFrameEdges="Bottom", thus cutting the ResizeGrip from view.

You can see this if you (frantically) drag the window over your screen - you'll see the ResizeGrip flickering.

To solve this we need to define a new WindowChrome with NonClientFrameEdges="None" (or GlassFrameThickness = 0 or both) and assign it to the window only when IsGlassEnabled == true && AllowsTransparency == true (I'm using application resources defined in App.xaml and defining only NonClientFrameEdges="None"):

1. Add these namespaces to App.xaml:
    xmlns:ribbon="clr-namespace:Microsoft.Windows.Controls.Ribbon;assembly=RibbonControlsLibrary"
    xmlns:ribbonPrimitives="clr-namespace:Microsoft.Windows.Controls.Ribbon.Primitives;assembly=RibbonControlsLibrary"
    xmlns:shell="clr-namespace:Microsoft.Windows.Shell;assembly=Microsoft.Windows.Shell"

2. Add these resources:
    <ribbonPrimitives:RibbonWindowSmallIconConverter x:Key="RibbonWindowSmallIconConverter" />
    <shell:WindowChrome x:Key="WindowChromeWithGlassAndTransparency"
                        NonClientFrameEdges="None" />
    <Style x:Key="MyStyle"
           TargetType="{x:Type ribbon:RibbonWindow}">
        <Style.Triggers>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Path=IsGlassEnabled, Source={x:Static shell:SystemParameters2.Current}}"
                               Value="True" />
                    <Condition Binding="{Binding AllowsTransparency, RelativeSource={RelativeSource Mode=Self}}"
                               Value="False" />
                </MultiDataTrigger.Conditions>
                <Setter Property="shell:WindowChrome.WindowChrome"
                        Value="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type ribbon:Ribbon}, ResourceId=WindowChromeAeroWithGlass}}" />
            </MultiDataTrigger>
            <MultiDataTrigger>
                <MultiDataTrigger.Conditions>
                    <Condition Binding="{Binding Path=IsGlassEnabled, Source={x:Static shell:SystemParameters2.Current}}"
                               Value="True" />
                    <Condition Binding="{Binding AllowsTransparency, RelativeSource={RelativeSource Mode=Self}}"
                               Value="True" />
                </MultiDataTrigger.Conditions>
                <Setter Property="shell:WindowChrome.WindowChrome"
                        Value="{DynamicResource WindowChromeWithGlassAndTransparency}" />
            </MultiDataTrigger>
            <DataTrigger Binding="{Binding Path=IsGlassEnabled, Source={x:Static shell:SystemParameters2.Current}}"
                         Value="True">
                <!--This is the original setter of the chrome that makes all the trouble-->
                <!--<Setter Property="shell:WindowChrome.WindowChrome"
                    Value="{DynamicResource {ComponentResourceKey TypeInTargetAssembly={x:Type ribbon:Ribbon}, ResourceId=WindowChromeAeroWithGlass}}" />-->
                <Setter Property="Template">
                    <Setter.Value>
                        <ControlTemplate TargetType="{x:Type ribbon:RibbonWindow}">
                            <Grid>
                                <Border Name="PART_ClientAreaBorder"
                                        Background="{TemplateBinding Control.Background}"
                                        BorderBrush="{TemplateBinding Control.BorderBrush}"
                                        BorderThickness="{TemplateBinding Control.BorderThickness}"
                                        Margin="{Binding Path=WindowNonClientFrameThickness, Source={x:Static shell:SystemParameters2.Current}}" />
                                <Border BorderThickness="{Binding Path=(shell:WindowChrome.WindowChrome).ResizeBorderThickness, RelativeSource={RelativeSource TemplatedParent}}">
                                    <Grid>
                                        <Image Name="PART_Icon"
                                               shell:WindowChrome.IsHitTestVisibleInChrome="True"
                                               HorizontalAlignment="Left"
                                               VerticalAlignment="Top"
                                               Source="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=Icon, Converter={StaticResource RibbonWindowSmallIconConverter }}"
                                               Width="{Binding Path=SmallIconSize.Width, Source={x:Static shell:SystemParameters2.Current}}"
                                               Height="{Binding Path=SmallIconSize.Height, Source={x:Static shell:SystemParameters2.Current}}" />
                                        <AdornerDecorator>
                                            <ContentPresenter Name="PART_RootContentPresenter" />
                                        </AdornerDecorator>
                                        <ResizeGrip Name="WindowResizeGrip"
                                                    shell:WindowChrome.ResizeGripDirection="BottomRight"
                                                    HorizontalAlignment="Right"
                                                    VerticalAlignment="Bottom"
                                                    Visibility="Collapsed"
                                                    IsTabStop="False" />
                                    </Grid>
                                </Border>
                            </Grid>
                            <ControlTemplate.Triggers>
                                <Trigger Value="{x:Null}"
                                         Property="Icon">
                                    <Setter TargetName="PART_Icon"
                                            Property="Source"
                                            Value="/RibbonControlsLibrary;component/Images/GlassyDefaultSystemIcon.png" />
                                </Trigger>
                                <Trigger Property="WindowState"
                                         Value="Maximized">
                                    <Setter TargetName="PART_Icon"
                                            Property="Margin"
                                            Value="0,2,0,0" />
                                </Trigger>
                                <MultiTrigger>
                                    <MultiTrigger.Conditions>
                                        <Condition Property="ResizeMode"
                                                   Value="CanResizeWithGrip" />
                                        <Condition Property="WindowState"
                                                   Value="Normal" />
                                    </MultiTrigger.Conditions>
                                    <Setter TargetName="WindowResizeGrip"
                                            Property="Visibility"
                                            Value="Visible" />
                                </MultiTrigger>
                            </ControlTemplate.Triggers>
                        </ControlTemplate>
                    </Setter.Value>
                </Setter>
            </DataTrigger>
        </Style.Triggers>
    </Style>

3. In your window use the new style:
    <rib:RibbonWindow ....
                      Style="{StaticResource MyStyle}">

        ....
    </rib:RibbonWindow>

The DataTrigger is almost as is from the original style, with only one modification: I've commented the setter for the WindowChrome.

The MultiDataTriggers are my addition. They check the value of AllowsTransparency property and apply the right WindowChrome: the original if the value is false and one with NonClientFrameEdges="None" (you can also use GlassFrameThickness = 0 instead) if the value is true.

NOTE: this solution removes the ability to resize the window using the edges, resizing of the window is done only by the ResizeGrip.