.netwpfvb.netwpf-controlswpf-core

What makes my custom ContextMenu throw System.Windows.Data Error: 4?


I made a custom WPF ContextMenu to show buttons in a strip on top or at the bottom of the menu, much like the copy/paste buttons in the Windows 11 Explorer context menu.

Everything works, but in the debugging output window I get these errors:

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=HorizontalContentAlignment; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'HorizontalContentAlignment' (type 'HorizontalAlignment')

System.Windows.Data Error: 4 : Cannot find source for binding with reference 'RelativeSource FindAncestor, AncestorType='System.Windows.Controls.ItemsControl', AncestorLevel='1''. BindingExpression:Path=VerticalContentAlignment; DataItem=null; target element is 'MenuItem' (Name=''); target property is 'VerticalContentAlignment' (type 'VerticalAlignment')

Is there anything I can do to make these go away? I've even tried defining custom styles and templates for the MenuItems which for sure don't go and try to find an ItemsControl to get the HorizontalContentAlignment and VerticalContentAlignment properties, so where is this coming from?

This is the XAML for my custom ContextMenu:

    <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                        xmlns:controls="clr-namespace:Laila.Shell.Controls">
    
        <Style TargetType="{x:Type controls:ContextMenu}">
            <Setter Property="SnapsToDevicePixels" Value="True" />
            <Setter Property="Grid.IsSharedSizeScope" Value="true" />
            <Setter Property="Foreground" Value="Black" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type controls:ContextMenu}">
                        <Border Padding="3" x:Name="PART_Menu" Opacity="0" BorderBrush="#999999" BorderThickness="1" 
                                Background="#F0F0F0" Margin="0,0,6,6" UseLayoutRounding="True" SnapsToDevicePixels="True">
                            <Border.Triggers>
                                <EventTrigger RoutedEvent="Rectangle.Loaded">
                                    <BeginStoryboard>
                                        <Storyboard>
                                            <DoubleAnimation Duration="0:0:0.2" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_Menu" />
                                        </Storyboard>
                                    </BeginStoryboard>
                                </EventTrigger>
                            </Border.Triggers>
                            <Border.Effect>
                                <DropShadowEffect BlurRadius="3" Color="Black" ShadowDepth="3" Opacity="0.5" />
                            </Border.Effect>
                            <Grid>
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto" />
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="Auto" />
                                </Grid.RowDefinitions>
    
                                <Border x:Name="borderTop" Grid.Row="0" Background="#dfdfdf" Padding="2" Visibility="Visible">
                                    <StackPanel Orientation="Horizontal" x:Name="PART_ButtonsTop" />
                                </Border>
                                <ScrollViewer Grid.Row="1" x:Name="PART_ScrollViewer"
                                              HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto">
                                    <ItemsPresenter Margin="0,0,0,1" x:Name="PART_ItemsPresenter" />
                                </ScrollViewer>
                                <Border x:Name="borderBottom" Grid.Row="2" Background="#dfdfdf" Padding="2" Visibility="Visible">
                                    <StackPanel Orientation="Horizontal" x:Name="PART_ButtonsBottom" />
                                </Border>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="ShowButtonsTopOrBottom" Value="Bottom">
                                <Setter Property="Visibility" TargetName="borderTop" Value="Collapsed" />
                            </Trigger>
                            <Trigger Property="ShowButtonsTopOrBottom" Value="None">
                                <Setter Property="Visibility" TargetName="borderTop" Value="Collapsed" />
                            </Trigger>
                            <Trigger Property="ShowButtonsTopOrBottom" Value="Top">
                                <Setter Property="Visibility" TargetName="borderBottom" Value="Collapsed" />
                            </Trigger>
                            <Trigger Property="ShowButtonsTopOrBottom" Value="None">
                                <Setter Property="Visibility" TargetName="borderBottom" Value="Collapsed" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    </ResourceDictionary>

Edit: these are the styles and templates for my menu items:

        <SolidColorBrush x:Key="Menu.BorderBrush" Color="#999999"/>
        <SolidColorBrush x:Key="Menu.Background" Color="#F0F0F0"/>
        <SolidColorBrush x:Key="Menu.Foreground" Color="Black"/>
        <SolidColorBrush x:Key="MenuItem.Highlighted.BorderBrush" Color="#26A0DA"/>
        <SolidColorBrush x:Key="MenuItem.Highlighted.Background" Color="#C0DDEB"/>
        <SolidColorBrush x:Key="MenuItem.Highlighted.Foreground" Color="Black"/>
        <SolidColorBrush x:Key="MenuItem.Disabled.Foreground" Color="Gray"/>
        <Style x:Key="{x:Static MenuItem.SeparatorStyleKey}" TargetType="{x:Type Separator}">
            <Setter Property="Margin" Value="-10,0,0,0" />
        </Style>
        <Style TargetType="{x:Type Menu}">
            <Setter Property="Background" Value="Transparent"/>
            <Setter Property="Foreground" Value="{StaticResource Menu.Foreground}"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type Menu}">
                        <Border BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" 
                                Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" 
                                SnapsToDevicePixels="true">
                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
        <ControlTemplate x:Key="{ComponentResourceKey ResourceId=SubmenuItemTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}" TargetType="{x:Type MenuItem}">
            <Grid SnapsToDevicePixels="true">
                <Border x:Name="Bg" BorderThickness="1" Background="Transparent" />
                <Grid Height="22">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition SharedSizeGroup="MenuItemCheckColumnGroup" Width="Auto"/>
                        <ColumnDefinition SharedSizeGroup="MenuItemIconColumnGroup" Width="Auto"/>
                        <ColumnDefinition Width="4"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="37"/>
                        <ColumnDefinition SharedSizeGroup="MenuItemIGTColumnGroup" Width="Auto"/>
                        <ColumnDefinition Width="17"/>
                    </Grid.ColumnDefinitions>
                    <Border x:Name="GlyphPanel" Height="20" Margin="1" Visibility="Collapsed" Width="22">
                        <Image x:Name="Glyph" Width="16" Height="16" Source="pack://application:,,,/Laila.Shell;component/Images/check16.png" />
                    </Border>
                    <ContentPresenter Grid.Column="1" x:Name="Icon" Height="16" Width="16" ContentSource="Icon" Margin="4,1,1,1" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
                    <ContentPresenter Grid.Column="3" ContentSource="Header" VerticalAlignment="Center" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    <TextBlock Grid.Column="5" Margin="{TemplateBinding Padding}" VerticalAlignment="Center" Text="{TemplateBinding InputGestureText}"/>
                </Grid>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="Icon" Value="{x:Null}">
                    <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
                </Trigger>
                <Trigger Property="IsCheckable" Value="true">
                    <Setter Property="Visibility" TargetName="GlyphPanel" Value="Hidden"/>
                </Trigger>
                <Trigger Property="IsChecked" Value="true">
                    <Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
                </Trigger>
                <Trigger Property="IsHighlighted" Value="true">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Highlighted.Foreground}"/>
                    <Setter Property="Background" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.Background}"/>
                    <Setter Property="BorderBrush" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.BorderBrush}" />
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Disabled.Foreground}"/>
                    <Setter Property="Opacity" TargetName="Glyph" Value="0.30"/>
                    <Setter Property="Opacity" TargetName="Icon" Value="0.30"/>
                </Trigger>
                <Trigger Property="IsPressed" Value="true">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Highlighted.Foreground}"/>
                    <Setter Property="Background" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.Background}"/>
                    <Setter Property="BorderBrush" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.BorderBrush}" />
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <ControlTemplate x:Key="{ComponentResourceKey ResourceId=SubmenuContent, TypeInTargetAssembly={x:Type FrameworkElement}}" TargetType="{x:Type ContentControl}">
            <Border Padding="3" x:Name="PART_Menu" Opacity="0" BorderBrush="{StaticResource Menu.BorderBrush}" 
                    BorderThickness="1" Background="{StaticResource Menu.Background}" Margin="0,0,6,6">
                <Border.Triggers>
                    <EventTrigger RoutedEvent="Rectangle.Loaded">
                        <BeginStoryboard>
                            <Storyboard>
                                <DoubleAnimation Duration="0:0:0.2" To="1" Storyboard.TargetProperty="Opacity" Storyboard.TargetName="PART_Menu" />
                            </Storyboard>
                        </BeginStoryboard>
                    </EventTrigger>
                </Border.Triggers>
                <Border.Effect>
                    <DropShadowEffect BlurRadius="3" Color="Black" ShadowDepth="3" Opacity="0.5" />
                </Border.Effect>
                <ScrollViewer x:Name="PART_ScrollViewer"
                              HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto">
                    <ContentPresenter />
                </ScrollViewer>
            </Border>
        </ControlTemplate>
        <ControlTemplate x:Key="{ComponentResourceKey ResourceId=TopLevelHeaderTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}" TargetType="{x:Type MenuItem}">
            <Grid SnapsToDevicePixels="true">
                <Border x:Name="Bg" Background="{TemplateBinding Background}" BorderThickness="1">
                    <StackPanel Orientation="Horizontal">
                        <ContentPresenter x:Name="Icon" ContentSource="Icon" Margin="4,0,6,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
                        <Image x:Name="GlyphPanel" Width="16" Height="16" Source="pack://application:,,,/Laila.Shell;component/Images/check16.png" Margin="7,0,0,0" Visibility="Collapsed" VerticalAlignment="Center" />
                        <ContentPresenter ContentSource="Header" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" 
                                          SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" />
                    </StackPanel>
                </Border>
                <Popup x:Name="PART_Popup" AllowsTransparency="true" Focusable="false" HorizontalOffset="1" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" Placement="Bottom" VerticalOffset="-1">
                    <Border>
                        <ContentControl x:Name="SubMenuBorder" IsTabStop="false" Template="{DynamicResource {ComponentResourceKey ResourceId=SubmenuContent, TypeInTargetAssembly={x:Type FrameworkElement}}}">
                            <ScrollViewer x:Name="PART_ScrollViewer"
                                          HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto">
                                <Grid RenderOptions.ClearTypeHint="Enabled">
                                    <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="true" Margin="2" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
                                </Grid>
                            </ScrollViewer>
                        </ContentControl>
                    </Border>
                </Popup>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="Icon" Value="{x:Null}">
                    <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
                </Trigger>
                <Trigger Property="IsChecked" Value="true">
                    <Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
                    <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
                </Trigger>
                <Trigger Property="IsHighlighted" Value="true">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Highlighted.Foreground}"/>
                    <Setter Property="Background" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.Background}"/>
                    <Setter Property="BorderBrush" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.BorderBrush}" />
                </Trigger>
                <Trigger Property="IsKeyboardFocused" Value="true">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Highlighted.Foreground}"/>
                    <Setter Property="Background" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.Background}"/>
                    <Setter Property="BorderBrush" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.BorderBrush}" />
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Disabled.Foreground}"/>
                    <Setter Property="Opacity" TargetName="GlyphPanel" Value="0.30"/>
                    <Setter Property="Opacity" TargetName="Icon" Value="0.30"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <ControlTemplate x:Key="{ComponentResourceKey ResourceId=TopLevelItemTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}" TargetType="{x:Type MenuItem}">
            <Grid SnapsToDevicePixels="true">
                <Border x:Name="Bg" BorderThickness="1" Background="Transparent"/>
                <DockPanel>
                    <ContentPresenter x:Name="Icon" ContentSource="Icon" Margin="4,0,6,0" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
                    <Image x:Name="GlyphPanel" Width="16" Height="16" Source="pack://application:,,,/Laila.Shell;component/Images/check16.png" Margin="7,0,0,0" Visibility="Collapsed" VerticalAlignment="Center" />
                    <ContentPresenter ContentSource="Header" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                </DockPanel>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="Icon" Value="{x:Null}">
                    <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
                </Trigger>
                <Trigger Property="IsChecked" Value="true">
                    <Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
                    <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
                </Trigger>
                <Trigger Property="IsHighlighted" Value="true">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Highlighted.Foreground}"/>
                    <Setter Property="Background" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.Background}"/>
                    <Setter Property="BorderBrush" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.BorderBrush}" />
                </Trigger>
                <Trigger Property="IsKeyboardFocused" Value="true">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Highlighted.Foreground}"/>
                    <Setter Property="Background" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.Background}"/>
                    <Setter Property="BorderBrush" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.BorderBrush}" />
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Disabled.Foreground}"/>
                    <Setter Property="Opacity" TargetName="GlyphPanel" Value="0.30"/>
                    <Setter Property="Opacity" TargetName="Icon" Value="0.30"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>
        <Geometry x:Key="RightArrow">M 0,0 L 4,3.5 L 0,7 Z</Geometry>
        <ControlTemplate x:Key="{ComponentResourceKey ResourceId=SubmenuHeaderTemplateKey, TypeInTargetAssembly={x:Type MenuItem}}" TargetType="{x:Type MenuItem}">
            <Grid SnapsToDevicePixels="true">
                <Border x:Name="Bg" BorderThickness="1" Background="Transparent"/>
                <Grid Height="22">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition SharedSizeGroup="MenuItemCheckColumnGroup" Width="Auto"/>
                        <ColumnDefinition SharedSizeGroup="MenuItemIconColumnGroup" Width="Auto"/>
                        <ColumnDefinition Width="4"/>
                        <ColumnDefinition Width="*"/>
                        <ColumnDefinition Width="37"/>
                        <ColumnDefinition SharedSizeGroup="MenuItemIGTColumnGroup" Width="Auto"/>
                        <ColumnDefinition Width="17"/>
                    </Grid.ColumnDefinitions>
                    <Border x:Name="GlyphPanel" BorderBrush="#CDD3E6" BorderThickness="1" Background="#E6EFF4" CornerRadius="3" Height="20" Margin="1" Visibility="Collapsed" Width="22">
                        <Image x:Name="Glyph" Width="16" Height="16" Source="pack://application:,,,/Laila.Shell;component/Images/check16.png" />
                    </Border>
                    <ContentPresenter Grid.Column="1" x:Name="Icon" Height="16" Width="16" ContentSource="Icon" Margin="4,1,1,1" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center"/>
                    <ContentPresenter Grid.Column="3" ContentSource="Header" VerticalAlignment="Center" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    <TextBlock Grid.Column="5" Margin="{TemplateBinding Padding}" VerticalAlignment="Center" Text="{TemplateBinding InputGestureText}" Visibility="Collapsed"/>
                    <Path Grid.Column="6" Data="{StaticResource RightArrow}" Fill="{TemplateBinding Foreground}" Margin="4,0,0,0" VerticalAlignment="Center"/>
                </Grid>
                <Popup x:Name="PART_Popup" AllowsTransparency="true" Focusable="false" HorizontalOffset="-2" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" Placement="Right" VerticalOffset="-3">
                    <ContentControl x:Name="SubMenuBorder" IsTabStop="false" Template="{DynamicResource {ComponentResourceKey ResourceId=SubmenuContent, TypeInTargetAssembly={x:Type FrameworkElement}}}">
                        <ScrollViewer x:Name="PART_ScrollViewer"
                                      HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Auto">
                            <Grid RenderOptions.ClearTypeHint="Enabled">
                                <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="true" Margin="2" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
                            </Grid>
                        </ScrollViewer>
                    </ContentControl>
                </Popup>
            </Grid>
            <ControlTemplate.Triggers>
                <Trigger Property="Icon" Value="{x:Null}">
                    <Setter Property="Visibility" TargetName="Icon" Value="Collapsed"/>
                </Trigger>
                <Trigger Property="IsCheckable" Value="true">
                    <Setter Property="Visibility" TargetName="GlyphPanel" Value="Hidden"/>
                </Trigger>
                <Trigger Property="IsChecked" Value="true">
                    <Setter Property="Visibility" TargetName="GlyphPanel" Value="Visible"/>
                </Trigger>
                <Trigger Property="IsHighlighted" Value="true">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Highlighted.Foreground}"/>
                    <Setter Property="Background" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.Background}"/>
                    <Setter Property="BorderBrush" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.BorderBrush}" />
                </Trigger>
                <Trigger Property="IsKeyboardFocused" Value="true">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Highlighted.Foreground}"/>
                    <Setter Property="Background" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.Background}"/>
                    <Setter Property="BorderBrush" TargetName="Bg" Value="{StaticResource MenuItem.Highlighted.BorderBrush}" />
                </Trigger>
                <Trigger Property="IsEnabled" Value="false">
                    <Setter Property="Foreground" Value="{StaticResource MenuItem.Disabled.Foreground}"/>
                    <Setter Property="Opacity" TargetName="GlyphPanel" Value="0.30"/>
                    <Setter Property="Opacity" TargetName="Icon" Value="0.30"/>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

Solution

  • Apparently this is caused by the default MenuItem style, which wasn't adapted yet, as I only redefined the ControlTemplates for the different types of MenuItems.

    I got rid of these messages by adding this to my application-wide styles:

        <Style TargetType="{x:Type MenuItem}">
            <Setter Property="HorizontalContentAlignment" Value="Left"/>
            <Setter Property="VerticalContentAlignment" Value="Center"/>
        </Style>