代码之家  ›  专栏  ›  技术社区  ›  Jader Dias

如何将样式应用于类及其子类?

  •  6
  • Jader Dias  · 技术社区  · 14 年前

    我想将以下样式应用于从 ButtonBase

    <Style
        TargetType="{x:Type ButtonBase}">
        <Setter
            Property="Cursor"
            Value="Hand" />
    </Style>
    

    但它只适用于给定的类,而不适用于其后代。如何实现我的目标?

    2 回复  |  直到 13 年前
        1
  •  4
  •   Robert Rossney    14 年前

    这不起作用,因为当元素没有显式指定样式时,WPF通过调用 FindResource ,使用元素的类型作为键。你已经创建了一个样式,它的键是 ButtonBase 无所谓:WPF找到键为 Button ToggleButton 使用它。

    基于继承的查找方法将使用元素的类型查找样式,如果找不到元素类型的样式,则使用基类型(并继续进行,直到找到样式或命中 FrameworkElement ). 问题是,只有在找不到匹配项时才起作用-即,如果没有 按钮 ,当然有。

    你可以做两件事。一是按照Jens的建议,使用 BasedOn 属性来实现您自己的样式层次结构不过,这有点烦人,因为必须为每个类型定义一种样式;如果不定义,则将使用该类型的默认WPF样式。

    另一种方法是使用 StyleSelector 实现此查找行为的。这样地:

    public class InheritanceStyleSelector : StyleSelector
    {
        public InheritanceStyleSelector()
        {
            Styles = new Dictionary<object, Style>();
        }
        public override Style SelectStyle(object item, DependencyObject container)
        {
            Type t = item.GetType();
            while(true)
            {
                if (Styles.ContainsKey(t))
                {
                    return Styles[t];
                }
                if (t == typeof(FrameworkElement) || t == typeof(object))
                {
                    return null;
                }
                t = t.BaseType;
            }
        }
    
        public Dictionary<object, Style> Styles { get; set; }
    }
    

    您可以创建此实例,为其提供一组样式,然后将其附加到任何 ItemsControl :

    <Window x:Class="StyleSelectorDemo.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:StyleSelectorDemo="clr-namespace:StyleSelectorDemo" Title="MainWindow" Height="350" Width="525">
        <Window.Resources>
            <StyleSelectorDemo:InheritanceStyleSelector x:Key="Selector">
                <StyleSelectorDemo:InheritanceStyleSelector.Styles>
                    <Style x:Key="{x:Type ButtonBase}">
                        <Setter Property="ButtonBase.Background"
                                Value="Red" />
                    </Style>
                    <Style x:Key="{x:Type ToggleButton}">
                        <Setter Property="ToggleButton.Background"
                                Value="Yellow" />
                    </Style>
                </StyleSelectorDemo:InheritanceStyleSelector.Styles>
            </StyleSelectorDemo:InheritanceStyleSelector>
        </Window.Resources>
        <Grid>
            <ItemsControl ItemContainerStyleSelector="{StaticResource Selector}">
                <Button>This is a regular Button</Button>
                <ToggleButton>This is a ToggleButton.</ToggleButton>
                <TextBox>This uses WPF's default style.</TextBox>
            </ItemsControl>
        </Grid>
    </Window>
    
        2
  •  3
  •   Jens    14 年前

    这似乎确实是造型系统的一个局限。

    面对这个问题,我声明了一些基本样式,并为我关心的每个后代“子样式化”。

    <Style x:Key="ButtonBaseStyle" TargetType="{x:Type ButtonBase}">
        <!-- Style stuff -->
    </Style>
    <Style TargetType="{x:Type Button}" BasedOn="{StaticResource ButtonBaseStyle}">
        <!-- Additional style stuff for button only -->
    </Style>
    <Style TargetType="{x:Type ToggleButton}" BasedOn="{StaticResource ButtonBaseStyle}">
        <!-- Additional style stuff for toggle button only -->
    </Style>
    <!-- more ButtonBase descendants here  -->