wpf 在使用用户定义模板的菜单项中插入图标

isr3a4wc  于 2022-11-26  发布在  其他
关注(0)|答案(1)|浏览(150)

我想有一个下拉菜单,菜单项的背景颜色是自定义的。我可以通过这个answer来实现。我的GUI中的根菜单项只有一个图标,没有Header。我用来定义菜单项图标的代码如下:

<Style x:Key="MenuIcon" TargetType="{x:Type MenuItem}">
    <Setter Property="SnapsToDevicePixels" Value="True" />
    <Setter Property="OverridesDefaultStyle" Value="True" />
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="{x:Type MenuItem}">
                 <Menu Background="Orange">
                     <MenuItem ToolTip="Menu" BorderBrush="White">
                          <MenuItem.Header>
                               <StackPanel
                                   Width="60"
                                   Height="50"
                                   HorizontalAlignment="Center"
                                   VerticalAlignment="Center"
                                   Background="Orange"
                                   Orientation="Horizontal">
                                   <Viewbox
                                       Margin="9"
                                       HorizontalAlignment="Center"
                                       VerticalAlignment="Center"
                                       Stretch="Fill">
                                       <Grid Margin="-8,0,0,0">
                                          <Path
                                              x:Name="MenuIconFillStyle"
                                              HorizontalAlignment="Center"
                                              VerticalAlignment="Center"
                                              Data="M6 36v-3h36v3Zm0-10.5v-3h36v3ZM615v-3h36v3Z"
                                              Fill="White" />
                                       </Grid>
                                   </Viewbox>
                               </StackPanel>
                           </MenuItem.Header>
                        </MenuItem>
                     </Menu>

                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                             <Setter TargetName="MenuIconFillStyle" Property="Fill" Value="Yellow" />
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

我在取自here<ControlTemplate x:Key="MenuItemControlTemplate1" TargetType="{x:Type MenuItem}">中添加了以下内容:

<ContentPresenter x:Name="Icon" Content="{TemplateBinding Icon}" ContentSource="Icon" HorizontalAlignment="Center" Height="16" Margin="3" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" Width="16"/>

以及ControlTemplate.Triggers中的以下内容:

<Trigger Property="Icon" Value="True">
     <Setter Property="Visibility" TargetName="Icon" Value="Visible"/>
</Trigger>

Template="{DynamicResource MenuItemControlTemplate1}"如下:

<ControlTemplate x:Key="MenuItemControlTemplate1" TargetType="{x:Type MenuItem}">
            <Border x:Name="templateRoot" 
                    BorderBrush="#535353" 
                    CornerRadius="3" 
                    BorderThickness="1" 
                    Background="{TemplateBinding Background}" 
                    SnapsToDevicePixels="True">
                <Grid VerticalAlignment="Center">
                    <Grid.ColumnDefinitions>
                        <ColumnDefinition Width="Auto"/>
                        <ColumnDefinition Width="Auto"/>
                    </Grid.ColumnDefinitions>

                    <ContentPresenter x:Name="Icon" Content="{TemplateBinding Icon}" ContentSource="Icon" HorizontalAlignment="Center" Width="26" Height="16" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" VerticalAlignment="Center" />
                    <ContentPresenter ContentTemplate="{TemplateBinding HeaderTemplate}" Content="{TemplateBinding Header}" Grid.Column="1" ContentStringFormat="{TemplateBinding HeaderStringFormat}" ContentSource="Header" Margin="{TemplateBinding Padding}" RecognizesAccessKey="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                    <Popup x:Name="PART_Popup"  AllowsTransparency="True" Focusable="False" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" PopupAnimation="{DynamicResource {x:Static SystemParameters.MenuPopupAnimationKey}}" Placement="Bottom" HorizontalOffset="-2">
                        <Border x:Name="SubMenuBorder" BorderBrush="#595959" BorderThickness="1" Background="#3A3A3A" Padding="2">
                            <ScrollViewer x:Name="SubMenuScrollViewer" Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}">
                                <Grid RenderOptions.ClearTypeHint="Enabled">
                                    <Canvas HorizontalAlignment="Left" Height="0" VerticalAlignment="Top" Width="0">
                                        <Rectangle x:Name="OpaqueRect" Fill="{Binding Background, ElementName=SubMenuBorder}" Height="{Binding ActualHeight, ElementName=SubMenuBorder}" Width="{Binding ActualWidth, ElementName=SubMenuBorder}"/>
                                    </Canvas>
                                    <ItemsPresenter x:Name="ItemsPresenter" KeyboardNavigation.DirectionalNavigation="Cycle" Grid.IsSharedSizeScope="True" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" KeyboardNavigation.TabNavigation="Cycle"/>
                                </Grid>
                            </ScrollViewer>
                        </Border>
                    </Popup>
                </Grid>
            </Border>
            <ControlTemplate.Triggers>
                <Trigger Property="Icon" Value="True">
                    <Setter Property="Visibility" TargetName="Icon" Value="Visible"/>
                </Trigger>
                <Trigger Property="IsSuspendingPopupAnimation" Value="True">
                    <Setter Property="PopupAnimation" TargetName="PART_Popup" Value="None"/>
                </Trigger>
                <Trigger Property="IsHighlighted" Value="True">
                    <Setter Property="Background" TargetName="templateRoot" Value="{StaticResource DarkBrush}"/>
                    <Setter Property="BorderBrush" TargetName="templateRoot" Value="#2C2C2C"/>
                    <Setter Property="BorderThickness" TargetName="templateRoot" Value="1"></Setter>
                </Trigger>

                <Trigger Property="CanContentScroll" SourceName="SubMenuScrollViewer" Value="False">
                    <Setter Property="Canvas.Top" TargetName="OpaqueRect" Value="{Binding VerticalOffset, ElementName=SubMenuScrollViewer}"/>
                    <Setter Property="Canvas.Left" TargetName="OpaqueRect" Value="{Binding HorizontalOffset, ElementName=SubMenuScrollViewer}"/>
                </Trigger>
                <Trigger Property="IsKeyboardFocusWithin" Value="True">
                    <Setter TargetName="templateRoot" Property="Background" Value="{StaticResource Clicked}" />
                    <Setter Property="Header" Value="Test" />
                    <Setter Property="BorderBrush" Value="#2C2C2C"></Setter>
                    <Setter Property="BorderThickness" Value="1"></Setter>
                </Trigger>
            </ControlTemplate.Triggers>
        </ControlTemplate>

MenuItem的自订背景和图标会指定为下列程式码片段:

<Grid Background="#535353">
    <Menu Width="100" Height="22" Margin="10, 10, 5, 5" HorizontalAlignment="Left" Background="White" VerticalAlignment="Top">
        <MenuItem Style="{StaticResource MenuIcon}" Template="{DynamicResource MenuItemControlTemplate1}">
    </Menu>
</Grid>

Style中定义的图标没有在MenuItem中与用于设置背景颜色的模板(Template="{DynamicResource MenuItemControlTemplate1}")沿着呈现。如何实现这一点?

编辑

根据@mm8的建议,我尝试将负责更改背景颜色的样式(从here中借用的带有x:Key="TopLevelHeaderStyle"的样式)与在根菜单中插入菜单项图标相结合,并得出以下结果:

<Style x:Key="TopLevelHeaderStyle" TargetType="{x:Type MenuItem}">
            <Setter Property="Background" Value="#000d18"/>
            <Setter Property="Foreground" Value="#d8d8d8"/>
            <Setter Property="Width" Value="72"/>
            <Setter Property="Height" Value="42"/>
            <Setter Property="FontSize" Value="16"/>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type MenuItem}">
                        <Border x:Name="MenuItemBorder" Width="72" Height="42" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}">
                            <Grid VerticalAlignment="Center">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="Auto"/>
                                    <ColumnDefinition Width="Auto"/>
                                </Grid.ColumnDefinitions>
                                <ContentPresenter Content="{TemplateBinding Header}" ContentSource="Header" Margin="{TemplateBinding Padding}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                <Popup AllowsTransparency="True" IsOpen="{Binding IsSubmenuOpen, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" PlacementTarget="{Binding ElementName=MenuItemBorder}"
                                   HorizontalOffset="1" VerticalOffset="-1">
                                    <Border BorderBrush="#414141" Background="#414141">
                                        <ScrollViewer Style="{DynamicResource {ComponentResourceKey ResourceId=MenuScrollViewer, TypeInTargetAssembly={x:Type FrameworkElement}}}">
                                            <ItemsPresenter SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
                                        </ScrollViewer>
                                    </Border>
                                </Popup>
                            </Grid>
                        </Border>
                        <ControlTemplate.Triggers>
                            <Trigger Property="IsHighlighted" Value="True">
                                <Setter Property="Background" Value="#1271C8"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

        <!--MenuIcon-->
        <Style x:Key="MenuIcon" TargetType="{x:Type MenuItem}" BasedOn="{StaticResource TopLevelHeaderStyle}">
            <Setter Property="SnapsToDevicePixels" Value="True" />
            <Setter Property="OverridesDefaultStyle" Value="True" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type MenuItem}">
                        <Menu>
                            <MenuItem>
                                <MenuItem.Header>
                                    <StackPanel
                            Width="60"
                            Height="50"
                            HorizontalAlignment="Center"
                            VerticalAlignment="Center"
                            Background="Orange"
                            Orientation="Horizontal">
                                        <Viewbox
                                Margin="9"
                                HorizontalAlignment="Center"
                                VerticalAlignment="Center"
                                Stretch="Fill">
                                            <Grid Margin="-8,0,0,0">
                                                <Path x:Name="MenuIconFillStyle"
                                        HorizontalAlignment="Center"
                                        VerticalAlignment="Center"
                                        Fill="White"              
                                        Data="M6 36v-3h36v3Zm0-10.5v-3h36v3ZM6 15v-3h36v3Z"
                                       />
                                            </Grid>
                                        </Viewbox>
                                    </StackPanel>
                                </MenuItem.Header>
                            </MenuItem>
                        </Menu>

并使用它如下:

<Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="50" />
            <RowDefinition />
        </Grid.RowDefinitions>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="auto" />
            <ColumnDefinition Width="*" />
        </Grid.ColumnDefinitions>

        <Menu Grid.Column="0" FontSize="24" HorizontalAlignment="Left" VerticalAlignment="Top">
            <MenuItem  Header="File" Style="{StaticResource TopLevelHeaderStyle}">
                <MenuItem Header="New"/>
                <MenuItem Header="Open"/>
                <MenuItem Header="Close"/>
            </MenuItem>
        </Menu>

        <Menu Grid.Column="1"  FontSize="24" HorizontalAlignment="Left" VerticalAlignment="Top">
            <MenuItem Margin="-11, 0,0,0" Width="50" Header="File" Style="{StaticResource MenuIcon}">
                <MenuItem Header="New1"/>
                <MenuItem Header="Open1"/>
                <MenuItem Header="Close1"/>
            </MenuItem>
        </Menu>
    </Grid>

现在,在根菜单项中具有图标的下拉菜单未显示其他菜单项内容New1Open1Close1我犯了什么错误?

roejwanj

roejwanj1#

MenuItem控件有一个名为“Icon”的Object类型DependencyProperty。此属性专为您的特定用途而保留。
首先,您需要将MenuItem ControlTemplate中Path中的Data绑定到父MenuItem的Icon属性。如下所示:

<Path x:Name="MenuIconFillStyle"
   HorizontalAlignment="Center"
   VerticalAlignment="Center"
   Data="{TemplateBinding Icon}"
   Fill="White" />

现在你可以像这样在XAML中指定一个PathGeometry。它的内容将是你的SVG数据:

<PathGeometry x:Key="MySpecialPath">M2 0C0.89687</PathGeometry>

最后,使用其Key将此路径作为StaticResource应用于任何MenuItem:

<Menu Width="100" Height="22" Margin="10, 10, 5, 5" HorizontalAlignment="Left" Background="White" VerticalAlignment="Top">
    <MenuItem Template="{DynamicResource MenuItemControlTemplate1}"
              Icon="{StaticResource MySpecialPath}">
</Menu>

如果你想对图标有更多的控制(多种颜色,不同尺寸,边距,它更复杂一些。只要记住MenuItem上的“Path”属性是一个对象,因此您可以假设使用任何“Presenting”元素将其绑定到MenuItem.Path -然后将任何类型的“Presented”对象传递给MenuItem(不需要是PathGeometry)。您可以使用

<ContentPresenter Content="{TemplateBinding Icon}" />

而不是MenuItemControlTemplate中的Path控件-然后将任何“Icon”控件赋予XAML中的MenuItem.Path属性。

相关问题