Проблема с установкой переднего плана с помощью Visual State Manager - PullRequest
9 голосов
/ 05 сентября 2010

У меня есть приложение WPF, и я пытаюсь стилизовать TextBox с помощью .Net v4 Visual State Manager. В частности, я пытаюсь установить цвета переднего плана и фона для состояния MouseOver.

То, что происходит, - то, что, в то время как фон и граница изменяются отлично, передний план - нет. Если кисти, которые я использую, получают свой цвет через StaticResource, то передний план вообще не меняется. Если кисти, которые я использую, получают свой цвет через DynamicResource, то, когда я нахожу курсор мыши на TextBox, изменяется передний план всех TextBox. Ясно, что либо я делаю что-то не так, либо то, что я хочу сделать, просто невозможно с VSM (что было бы довольно обидно).

Вот ресурсы, которые я использую:

<Color x:Key="ControlBackgroundColor" R="178" G="178" B="178" A="255" />
<Color x:Key="ControlForegroundColor" R="0" G="0" B="0" A="255" />
<Color x:Key="BorderColor" R="127" G="127" B="127" A="255" />
<Color x:Key="MouseOverControlBackgroundColor" R="0" G="0" B="0" A="255" />
<Color x:Key="MouseOverControlForegroundColor" R="255" G="255" B="255" A="255" />
<Color x:Key="MouseOverBorderColor" R="178" G="178" B="178" A="255" />

<SolidColorBrush PresentationOptions:Freeze="True" x:Key="ControlBackgroundBrush" Color="{DynamicResource ControlBackgroundColor}" />
<SolidColorBrush PresentationOptions:Freeze="True" x:Key="ControlForegroundBrush" Color="{DynamicResource ControlForegroundColor}" />
<SolidColorBrush PresentationOptions:Freeze="True" x:Key="BorderBrush" Color="{DynamicResource BorderColor}" />

<SolidColorBrush PresentationOptions:Freeze="True" x:Key="MouseOverControlBackgroundBrush" Color="{DynamicResource MouseOverControlBackgroundColor}" />
<SolidColorBrush PresentationOptions:Freeze="True" x:Key="MouseOverControlForegroundBrush" Color="{DynamicResource MouseOverControlForegroundColor}" />
<SolidColorBrush PresentationOptions:Freeze="True" x:Key="MouseOverBorderBrush" Color="{DynamicResource MouseOverBorderColor}" />

<Style TargetType="{x:Type TextBox}" >
    <Setter Property="BorderThickness" Value="1"/>
    <Setter Property="Padding" Value="2"/>
    <Setter Property="Margin" Value="1" />
    <Setter Property="BorderBrush" Value="{DynamicResource BorderBrush}" />
    <Setter Property="Background" Value="{DynamicResource ControlBackgroundBrush}" />
    <Setter Property="Foreground" Value="{DynamicResource ControlForegroundBrush}" />

    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="TextBox">
                <Grid x:Name="RootElement">
                    <VisualStateManager.VisualStateGroups>
                        <VisualStateGroup x:Name="CommonStates">
                            <VisualState x:Name="Normal"/>
                            <VisualState x:Name="MouseOver">
                                <Storyboard>
                                    <ColorAnimation Storyboard.TargetName="MouseOverBorder" Storyboard.TargetProperty="(Border.BorderBrush).(SolidColorBrush.Color)" To="{DynamicResource MouseOverBorderColor}" Duration="0:0:0.3"/>
                                    <ColorAnimation Storyboard.TargetName="MouseOverBorder" Storyboard.TargetProperty="(Border.Background).(SolidColorBrush.Color)" To="{DynamicResource MouseOverControlBackgroundColor}" Duration="0:0:0.3"/>
                                    <ColorAnimation Storyboard.TargetName="PART_ContentHost" Storyboard.TargetProperty="(Foreground).(SolidColorBrush.Color)" To="{DynamicResource MouseOverControlForegroundColor}" Duration="0:0:0.3"/>
                                </Storyboard>
                            </VisualState>
                        </VisualStateGroup>
                    </VisualStateManager.VisualStateGroups>
                    <Border x:Name="Border" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="1" Opacity="1" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}">
                        <Grid x:Name="ContentGrid">
                            <Border x:Name="MouseOverBorder" BorderThickness="1" BorderBrush="Transparent" Background="Transparent">
                                <ScrollViewer x:Name="PART_ContentHost" Padding="{TemplateBinding Padding}" Foreground="{TemplateBinding Foreground}" BorderThickness="0" IsTabStop="False"/>
                            </Border>
                        </Grid>
                    </Border>
                </Grid>
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

Мне очень странно, что фоновые и граничные кисти, которые создаются и анимируются одинаково, работают идеально независимо от того, использую я статические или динамические ресурсы, но цвет переднего плана - нет.

Если у кого-то есть какие-либо идеи или если есть лучший способ сделать это, я хотел бы услышать это.

Дэвид Маллин IMA Technologies

1 Ответ

16 голосов
/ 25 апреля 2011

VisualStateManager не может управлять свойствами, значения которых устанавливаются через привязку. В вашем примере для Background и BorderBrush установлены локальные значения (Transparent), и поэтому VSM может их анимировать. С другой стороны, Foreground устанавливается с использованием TemplateBinding, поэтому VSM не сможет его анимировать, если действует значение привязки.

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

Чистый эффект состоит в том, что я не думаю, что вы можете анимировать цвет текста переднего плана и позволять пользователю задавать цвет переднего плана.

...