使用带有ResourceDictionaries或MergedDictionaries的setter属性使用ItemsSource时的MenuItem样式

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用带有ResourceDictionaries或MergedDictionaries的setter属性使用ItemsSource时的MenuItem样式相关的知识,希望对你有一定的参考价值。

我有一个上下文菜单,并且从加载了XamlReader.Load()的ResourceDictionary中正确设置样式。我正在使用的样式键是一个DynamicResource,我称之为styleBanner。

在这个上下文菜单中,我有一个名为Skins的菜单项,它也可以使用上面的动态资源styleBanner保存。但是这个菜单项的子菜单项数据绑定到数据上下文View Model中的ItemsSource,这也正常工作。

我的麻烦是子菜单项没有正确设置样式。

这是什么工作,但没有得到风格:

<Window.ContextMenu>
    <ContextMenu DataContext="TimersHostViewModel" Name="TimersHostContextMenu" Style="{DynamicResource styleBanner}">
        <MenuItem Name="Skins" Header="Skins" ItemsSource="{Binding Source={StaticResource TimersHostViewModel}, Path=Skins}" Style="{DynamicResource styleBanner}">
            <MenuItem.ItemContainerStyle>
                <Style TargetType="MenuItem">
                    <Setter Property="Header" Value="{Binding Path=SkinName}"/>
                    <Setter Property="Command" Value="{Binding Source={StaticResource TimersHostViewModel}, Path=TimersHostContextMenuClickCommand}"/>
                    <Setter Property="CommandParameter" Value="{Binding Path=SkinName}"/>
                </Style>
            </MenuItem.ItemContainerStyle>
        </MenuItem>
    </ContextMenu>
</Window.ContextMenu>

所以这是我尝试过的一件事,我尝试添加以下行:

<Setter Property="Style" Value={DynamicResource styleBanner}"/>

像这样:

<Style TargetType="MenuItem">
    <Setter Property="Header" Value="{Binding Path=SkinName}"/>
    <Setter Property="Style" Value="{DynamicResource styleBanner}"/>
    <Setter Property="Command" Value="{Binding Source={StaticResource TimersHostViewModel}, Path=TimersHostContextMenuClickCommand}"/>
    <Setter Property="CommandParameter" Value="{Binding Path=SkinName}"/>
</Style>

我在尝试时遇到异常:System.ArgumentException {“不允许Style对象影响它所适用的对象的Style属性。”}

所以我试着这个改变上面添加的行如下:

<Setter Property="Template" Value="{DynamicResource styleBanner}"/>

然后我得到一个不同的异常:System.InvalidCastException {“无法将'System.Windows.Style'类型的对象强制转换为'System.Windows.FrameworkTemplate'。”}

那么这样做的正确方法是什么?我已经在互联网和Stackoverflow上搜索了一下,没有任何线索。


编辑:好的我看到使用以下内容现在可用于获取子菜单项上的样式集:

<Setter Property="ItemContainerStyle" Value="{DynamicResource styleBanner}"/>

但由于某种原因,styleBanner背景不用于子菜单项。

我应该从我的ResourceDictionary发布了styleBanner,所以这里是:

<!-- Banner Style -->
<Style x:Key="styleBanner">
  <Setter Property="StackPanel.Background">
    <Setter.Value>
      <LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1">
        <GradientStop Color="DarkGray" Offset="0.1" />
        <GradientStop Color="Black" Offset="1" />
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>
  <Setter Property="TextBlock.Foreground" Value="White" />
  <Setter Property="TextBlock.FontFamily" Value="TR2N" />
</Style>

以下是我现在对上下文菜单的看法:

<Window.ContextMenu>
    <ContextMenu DataContext="TimersHostViewModel" Name="TimersHostContextMenu" Style="{DynamicResource styleBanner}">
        <MenuItem Name="Skins" Header="Skins" ItemsSource="{Binding Source={StaticResource TimersHostViewModel}, Path=Skins}" Style="{DynamicResource styleBanner}">
            <MenuItem.ItemContainerStyle>
                <Style TargetType="MenuItem">
                    <Setter Property="Header" Value="{Binding Path=SkinName}"/>
                    <Setter Property="Command" Value="{Binding Source={StaticResource TimersHostViewModel}, Path=TimersHostContextMenuClickCommand}"/>
                    <Setter Property="CommandParameter" Value="{Binding Path=SkinName}"/>
                    <Setter Property="ItemContainerStyle" Value="{DynamicResource styleBanner}"/>
                </Style>
            </MenuItem.ItemContainerStyle>
        </MenuItem>
    </ContextMenu>
</Window.ContextMenu>

这是一张显示我得到的风格差异的图片:

因此,您可以看到应用了字体和字体颜色,但是使用ResourceDictionary中定义的渐变画笔的styleBanner背景则不是。

实际上如果仔细观察我玩了一个小技巧,上面的ResourceDictionary中的styleBanner是从BlackSkin.xaml ResourceDictionary发布的,它的渐变背景应该是深灰色,但屏幕截图显示的是蓝色背景,因为我有一个BlueSkin.xaml ResourceDictionary,但它们都很相似,并且都具有相同的行为,所以这里是BlueSkin.xaml ResourceDictionary的styleBanner,为了完整性:

<!-- Banner Style -->
<Style x:Key="styleBanner">
  <Setter Property="StackPanel.Background">
    <Setter.Value>
      <LinearGradientBrush StartPoint="0,0.25" EndPoint="1,0.5">
        <GradientStop Color="#CC0088DD" Offset="0.3" />
        <GradientStop Color="#3300FFFF" Offset="0.85" />
      </LinearGradientBrush>
    </Setter.Value>
  </Setter>
  <Setter Property="TextBlock.Foreground" Value="Yellow" />
  <Setter Property="TextBlock.FontFamily" Value="Comic Sans MS" />
</Style>
答案

您无法在Style中设置Style属性。

将StyleBanner设置为样式中的ItemContainerStyle,例如ContextMenuStyle

例如。让我们将您的样式名称命名为ContextMenuStyle,并将其ItemContainer样式设置为StyleBanner

<Style x:Key="ContextMenuStyle" TargetType="MenuItem">
    <Setter Property="Header" Value="{Binding Path=SkinName}"/>
    <Setter Property="Command" Value="{Binding Source={StaticResource TimersHostViewModel}, Path=TimersHostContextMenuClickCommand}"/>
    <Setter Property="CommandParameter" Value="{Binding Path=SkinName}"/>
    <Setter Property="ItemContainerStyle" Value="{DynamicResource styleBanner}"/>
</Style>

现在,您可以在上下文菜单中指定以下样式:

<ContextMenu.Style>
    <StaticResource ResourceKey="ContextMenuStyle"></StaticResource>
</ContextMenu.Style>

希望你能得到这个想法......决定哪个属于style并且属于ContextMenuStyle并为控件设置Style,你可以在样式中设置ContextMenuStyle。您甚至可以在ContextMenuStyle中嵌套styleBanner,这将适用于子菜单

编辑:

你是对的,背景不会被转移到子菜单项。在这种情况下,现在剩下的唯一选择是使用背景定义ControlTemplate,尝试以下方法:

<Setter Property="Template">
    <Setter.Value>
        <ControlTemplate>
            <Border >
                <Border.Background>
                    <LinearGradientBrush StartPoint="0,0.25" EndPoint="1,0.5">
                        <GradientStop Color="#CC0088DD" Offset="0.3" />
                        <GradientStop Color="#3300FFFF" Offset="0.85" />
                    </LinearGradientBrush>
                </Border.Background>
                <Button Content="{Binding Path=SkinName}" Command="{Binding Source={StaticResource TimersHostViewModel}, Path=TimersHostContextMenuClickCommand}" 
                        CommandParameter="{Binding Path=SkinName}"
                        Foreground="Yellow" FontFamily="Comic Sans MS"></Button>
            </Border>
        </ControlTemplate>
    </Setter.Value>
</Setter>
另一答案

您可以使用“BasedOn”属性:

<MenuItem.ItemContainerStyle>
  <Style BasedOn="{StaticResource ISAMenu}" TargetType="MenuItem">
      <Setter Property="Command" Value="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=MenuItem}, Path=DataContext.ChangeLanguageCommand}" />
      <Setter Property="CommandParameter" Value="{Binding}" />
  </Style>
</MenuItem.ItemContainerStyle>

然后在你的App.xaml中引用一个字典

<ResourceDictionary.MergedDictionaries>
   <ResourceDictionary Source="Assets/ResourceDictionaries/NavBarMenu.xaml" />
 </ResourceDictionary.MergedDictionaries>

最后在NavBar Menu.xaml中

<Style x:Key="ISAMenu" TargetType="{x:Type MenuItem}">

这是一个老问题,但我花了几个小时找出另一个干净的解决方案,所以我希望它可以帮助别人。

以上是关于使用带有ResourceDictionaries或MergedDictionaries的setter属性使用ItemsSource时的MenuItem样式的主要内容,如果未能解决你的问题,请参考以下文章

构建操作页面或资源

使用 SharedResourceDictionary 时的内存泄漏

在 ResourceDictionary 中交换 DynamicResource

将外部 Viewbox 导入到 UserControl

如何使用带有或不带有 Appium 的 Robot Framework 集成 WinAppDriver?

使用带有 ADO 的 Excel 2010 VBA(或带有 LINQ 的 vb.net)查询表的最佳 SQL 语句是啥