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

时间:2014-02-06 03:44:10

标签: c# wpf xaml styles 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>

这是一张显示我所获得的风格差异的图片: Difference in styles applied to different sections levels of the context menu.

所以你可以看到字体&amp;应用字体颜色,但是使用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>

1 个答案:

答案 0 :(得分:2)

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

在Style中将StyleBanner设置为ItemContainerStyle,例如ContextMenuStyle

E.g。让我们将您的样式名称命名为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>