Как применить стиль к классу и его потомкам? - PullRequest
6 голосов
/ 25 ноября 2010

Я хочу применить следующий стиль ко всем элементам управления, которые происходят от ButtonBase

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

Но он работает только для данного класса, а не для его потомков.Как добиться того, что я намерен?

Ответы [ 2 ]

4 голосов
/ 25 ноября 2010

Это не работает, потому что, когда элемент не имеет явно назначенного стиля, WPF находит свой стиль, вызывая FindResource, используя тип элемента в качестве ключа.Тот факт, что вы создали стиль с ключом ButtonBase, не имеет значения: WPF находит стиль с ключом Button или ToggleButton и использует его.

Поиск на основе наследованияМетод будет искать стиль, используя тип элемента, а затем использовать базовый тип, если стиль для типа элемента не найден (и продолжать работу, пока не найдет стиль или не нажмет FrameworkElement).Проблема в том, что работает, только если совпадение не найдено - то есть, если для Button нет стиля по умолчанию, что, конечно, есть.

Есть две вещи, которые вы можете сделать.Один из них - сделать то, что предлагает Дженс, используя свойство стиля 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>
3 голосов
/ 25 ноября 2010

Это действительно кажется ограничением системы стилей.

Столкнувшись с этой проблемой, я объявил некоторый базовый стиль и «подтипил» его для каждого потомка, которого я заботился.

<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  -->
...