1

如何为 WPF控件创建 2 种视觉状态:一种在和之间闪烁背景颜色;和一种将边框背景颜色设置回并停止闪烁的法线?BorderTransparentRedTransparent

注意: WPF控件在另一个控件的Border内部使用。ContentTemplate

我还要求当某些属性提到从toIsEnabledBorder变化时触发它们,反之亦然;并且 IsEnabled 属性绑定到 ViewModel 属性。当我们点击边框时- 闪烁应该停止并且背景应该恢复正常..FalseTrue

4

2 回答 2

4

如果您想纯粹在 xaml 中执行动画,那么您可以使用触发器而不是 VisualStateManager。以下内容应为您提供您所追求的行为:

 <Border Name="TheBorder" BorderThickness="5"
            Margin="30" Padding="20" >
        <Border.Background>
            <SolidColorBrush x:Name="BackgroundBrush" Color="Transparent" />
        </Border.Background>
        <Border.Style>
            <Style TargetType="{x:Type Border}">
                <Style.Triggers>
                    <Trigger Property="IsEnabled" Value="True">
                        <Trigger.EnterActions>
                            <BeginStoryboard Name="FlashStoryboard">
                                <Storyboard>
                                    <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background"
                                                                   Duration="0:0:1" RepeatBehavior="Forever">
                                        <ObjectAnimationUsingKeyFrames.KeyFrames>
                                            <DiscreteObjectKeyFrame KeyTime="0:0:0.5">
                                                <DiscreteObjectKeyFrame.Value>
                                                    <SolidColorBrush Color="Red"/>
                                                </DiscreteObjectKeyFrame.Value>
                                            </DiscreteObjectKeyFrame>
                                        </ObjectAnimationUsingKeyFrames.KeyFrames>
                                    </ObjectAnimationUsingKeyFrames>
                                </Storyboard>
                            </BeginStoryboard>
                        </Trigger.EnterActions>
                        <Trigger.ExitActions>
                            <StopStoryboard BeginStoryboardName="FlashStoryboard"></StopStoryboard>
                        </Trigger.ExitActions>
                    </Trigger>
                </Style.Triggers>
            </Style>
        </Border.Style>
    </Border>
于 2013-06-05T07:30:30.097 回答
3

您可以使用 VisualStateManager 定义 VisualStates。要在 Border 上获得您想要的行为,以下应该是一个很好的起点:

xml:

  <Border Name="TheBorder" BorderThickness="5"
            Margin="30" Padding="20"
            wpfApplication1:StateManager.VisualState="{Binding ElementName=TheBorder,
                                                               Path=IsEnabled, Mode=TwoWay,
                                                               Converter={StaticResource EnabledToVisualStateConverter}}">
        <Border.Background>
            <SolidColorBrush x:Name="BackgroundBrush" Color="Transparent"/>
        </Border.Background>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup Name="Common">
                <VisualState x:Name="Normal"/>
                <VisualState x:Name="Flash">
                    <Storyboard>
                        <ColorAnimation Storyboard.TargetName="BackgroundBrush" 
                                        Storyboard.TargetProperty="Color" To="Red"
                                        RepeatBehavior="Forever"/>
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
    </Border>

转换器:

    public class EnabledToVisualStateConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        var isEnabled = (bool) value;
        if (isEnabled)
            return "Flash";

        return "Normal";
    }

    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

用于更改 VisualState 的 StateManager 类:

    public class StateManager
{
    private static string _valueToApplyOnInitialization;

    public static readonly DependencyProperty VisualStateProperty =
        DependencyProperty.RegisterAttached("VisualState", typeof (string), typeof (StateManager),
                                            new PropertyMetadata(VisualStateChangeCallback));

    public static string GetVisualState(DependencyObject obj)
    {
        return (string)obj.GetValue(VisualStateProperty);
    }
    public static void SetVisualState(DependencyObject obj, string value)
    {
        obj.SetValue(VisualStateProperty, value);
    }

    public static void VisualStateChangeCallback(object sender, DependencyPropertyChangedEventArgs args)
    {
        var element = sender as FrameworkElement;
        if (element == null)
            return;

        if (!element.IsInitialized)
        {
            _valueToApplyOnInitialization = (String) args.NewValue;
            element.Initialized += OnElementInitialized;
        }
        else
            VisualStateManager.GoToElementState(element, (string)args.NewValue, true);
    }

    private static void OnElementInitialized(object sender, EventArgs e)
    {
        var element = sender as FrameworkElement;
        if (element == null)
            return;

        VisualStateManager.GoToElementState(element, _valueToApplyOnInitialization, true);
        element.Initialized -= OnElementInitialized;
    }
}

如果您想使用 ViewModel 中的属性而不是 Border 上的 IsEnabled 属性,则只需将 Binding to 'TheBorder' 替换为 ViewModel 属性。

于 2013-06-04T20:36:08.367 回答