Search code examples
wpfxamlpopupstylesribbon

Why does my Ribbon Menu Button Popup disappear when I apply this Style?


Here is my XAML:

<Ribbon x:Name="ribbonMain" Height="200" ContextMenu="{x:Null}" VerticalAlignment="Top" ShowQuickAccessToolBarOnTop="False" >

    <RibbonTab x:Name="ribbonTabMain" Header="Test Tab" ContextMenu="{x:Null}" >

        <RibbonGroup x:Name="ribbonGroupMain" Header="Test Group" ContextMenu="{x:Null}">
            <RibbonButton x:Name="ribbonButtonMain" Label="Test Button" ContextMenu="{x:Null}" />
        </RibbonGroup>

        <RibbonGroup x:Name="ribbonGroupMain2" Header="Test Group 2" ContextMenu="{x:Null}">
            <RibbonMenuButton ContextMenu="{x:Null}" Name="ribbonMenuButtonMain" Label="Menu Button">
                <RibbonMenuItem ContextMenu="{x:Null}" Name="ribbonMenuItemMain" Header="Menu Item"></RibbonMenuItem>
                <RibbonMenuItem ContextMenu="{x:Null}" Name="ribbonMenuItemMain2" Header="Menu Item 2"></RibbonMenuItem>
            </RibbonMenuButton>
        </RibbonGroup>

    </RibbonTab>

</Ribbon>

I then run this C# Code to get the Ribbon Menu Button Default Control Template:

string ribbonMenuButtonControlTemplate = XamlWriter.Save(ribbonMenuButtonMain.Template);

After that I set the x:Name and x:Key properties of the Control Template to something and then put that string of XAML in this:

<Style TargetType="RibbonMenuButton" 
    <Setter Property="Template">
        <Setter.Value>
            {DefaultControlTemplateHere}
        </Setter.Value>
    </Setter>
</Style>

Last I put that Style in my <Window.Resources>.

I wanted to alter the Style from there, but then I realized that the popup just wasn't working anymore. I expected nothing to change. Seems I was mistaken. Why does this happen?

Note:

I've tried running this code to see if the popup would open:

if (!ribbonMenuButtonMain.IsDropDownOpen)
{
    ribbonMenuButtonMain.IsDropDownOpen = true;
}

With no Style applied that code runs fine and the popup opens. But with the Style I get this exception:

System.InvalidOperationException: 'This Visual is not connected to a PresentationSource.'


Solution

  • The XamlWriter.Save method has some serialization limitations that are mentioned here. One of them being that;

    Common references to objects made by various markup extension formats, such as StaticResource or Binding, will be dereferenced by the serialization process. These were already dereferenced at the time that in-memory objects were created by the application runtime, and the Save logic does not revisit the original XAML to restore such references to the serialized output.

    So your generated template is missing a TemplateBinding to the IsOpen property of the Popup:

    <Popup ... IsOpen="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=IsDropDownOpen}">
    

    You may extract the default template including any bindings from C:\Windows\Microsoft.NET\Framework64\v4.0.30319\WPF\System.Windows.Controls.Ribbon.dll using a decompiler such as for example dotPeek.