Как параметризовать стиль WPF? - PullRequest
1 голос
/ 17 марта 2010

Я ищу самый простой способ удалить дублирование в моем коде WPF.

Код ниже - простой светофор с 3 огнями - Red, Amber, Green. Он связан с ViewModel, у которого есть одно свойство enum State, принимающее одно из этих 3 значений.

Код, объявляющий 3 эллипса, очень дублирует. Теперь я хочу добавить анимацию, чтобы каждый источник света появлялся и исчезал - стили станут еще больше, а дублирование ухудшится.

Можно ли параметризовать стиль с помощью аргументов State и Color, чтобы у меня был один стиль в ресурсах, описывающих поведение источника света, а затем использовать его 3 раза - для 'Red', 'Amber' и ' Зеленые огни?

<UserControl.Resources>
    <l:TrafficLightViewModel x:Key="ViewModel" />
</UserControl.Resources>

<StackPanel Orientation="Vertical" DataContext="{StaticResource ViewModel}">
    <StackPanel.Resources>
        <Style x:Key="singleLightStyle" TargetType="{x:Type Ellipse}">
            <Setter Property="StrokeThickness" Value="2" />
            <Setter Property="Stroke" Value="Black" />
            <Setter Property="Height" Value="{Binding Width, RelativeSource={RelativeSource Self}}" />
            <Setter Property="Width" Value="60" />
            <Setter Property="Fill" Value="LightGray" />
        </Style>
    </StackPanel.Resources>

    <Ellipse>
        <Ellipse.Style>
            <Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource singleLightStyle}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding State}" Value="Red">
                        <Setter Property="Fill" Value="Red" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Ellipse.Style>
    </Ellipse>
    <Ellipse>
        <Ellipse.Style>
            <Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource singleLightStyle}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding State}" Value="Amber">
                        <Setter Property="Fill" Value="Red" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Ellipse.Style>
    </Ellipse>
    <Ellipse>
        <Ellipse.Style>
            <Style TargetType="{x:Type Ellipse}" BasedOn="{StaticResource singleLightStyle}">
                <Style.Triggers>
                    <DataTrigger Binding="{Binding State}" Value="Green">
                        <Setter Property="Fill" Value="Green" />
                    </DataTrigger>
                </Style.Triggers>
            </Style>
        </Ellipse.Style>
    </Ellipse>
</StackPanel>

1 Ответ

1 голос
/ 17 марта 2010

Пока ваш «Светофор» обернут внутри элемента управления, который, кажется, так и есть, я не думаю, что это ужасно. Каждый эллипс четко определен и имеет разные триггеры, каждый из которых указывает свое собственное состояние. Вы уже включили общие части в базовый стиль, и это хорошо.

Вы можете обернуть отдельные эллипсы внутри другого пользовательского элемента управления (для которого не требуется вспомогательная модель представления), который имеет свойство ActiveState и свойство ActiveFill. Тогда ваш TrafficLight выглядит примерно так:

<StackPanel Orientation="Vertical" DataContext="{StaticResource ViewModel}">
    <my:Indicator State="{Binding State}" ActiveState="Red" ActiveFill="Red" />
    <my:Indicator State="{Binding State}" ActiveState="Amber" ActiveFill="Red" />
    <my:Indicator State="{Binding State}" ActiveState="Green" ActiveFill="Green" />
</StackPanel>

Это позволяет вам обернуть все стили Ellipse в элемент управления Indicator, и единственное, о чем нужно беспокоиться, - это сравнение State с ActiveState, чтобы определить, должен ли он заполняться кистью ActiveFill ,

Что касается того, стоит ли это усилий или нет, это зависит от того, сколько из них у вас есть, и если вы используете их за пределами вашего пользовательского контроля светофора. Помните: вам это не нужно.

...