我想用DinamicResources为按钮的背景色设置动画。为此,我创建了附加的DependencyProperty:
namespace ModPlusStyle.Controls.Helpers
{
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
public class ButtonAssist
{
private static readonly Dictionary<Button, Color> _initBackgroundBrush = new Dictionary<Button, Color>();
private static readonly Dictionary<Button, Color> _initForegroundBrush = new Dictionary<Button, Color>();
public static readonly DependencyProperty AnimateMouseOverProperty = DependencyProperty.RegisterAttached(
"AnimateMouseOver",
typeof(bool),
typeof(ButtonAssist),
new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.AffectsRender, AnimateMouseOverChangedCallback));
public static void SetAnimateMouseOver(DependencyObject element, bool value)
{
element.SetValue(AnimateMouseOverProperty, value);
}
public static bool GetAnimateMouseOver(DependencyObject element)
{
return (bool)element.GetValue(AnimateMouseOverProperty);
}
private static void AnimateMouseOverChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is Button button)
{
if ((bool)e.NewValue)
{
button.MouseEnter += ButtonOnMouseEnter;
button.MouseLeave += ButtonOnMouseLeave;
}
else
{
button.MouseEnter -= ButtonOnMouseEnter;
button.MouseLeave -= ButtonOnMouseLeave;
}
}
}
private static void ButtonOnMouseEnter(object sender, MouseEventArgs e)
{
if (sender is Button button &&
!(button.Parent is WindowCommands) &&
button.Background is SolidColorBrush backgroundSolidColorBrush &&
button.Foreground is SolidColorBrush foregroundSolidColorBrush)
{
var parentWindow = Window.GetWindow(button);
if (parentWindow != null)
{
if (parentWindow.Resources["WhiteBrush"] is SolidColorBrush whiteBrush &&
parentWindow.Resources["BlackBrush"] is SolidColorBrush blackBrush)
{
if (_initBackgroundBrush.ContainsKey(button))
_initBackgroundBrush[button] = backgroundSolidColorBrush.Color;
else
_initBackgroundBrush.Add(button, backgroundSolidColorBrush.Color);
if (_initForegroundBrush.ContainsKey(button))
_initForegroundBrush[button] = foregroundSolidColorBrush.Color;
else
_initForegroundBrush.Add(button, foregroundSolidColorBrush.Color);
button.Background = new SolidColorBrush(backgroundSolidColorBrush.Color);
ColorAnimation backgroundColorAnimation = new ColorAnimation(
backgroundSolidColorBrush.Color,
whiteBrush.Color,
new Duration(TimeSpan.FromMilliseconds(300)));
button.Background.BeginAnimation(SolidColorBrush.ColorProperty, backgroundColorAnimation);
button.Foreground = new SolidColorBrush(foregroundSolidColorBrush.Color);
ColorAnimation foregroundColorAnimation = new ColorAnimation(
foregroundSolidColorBrush.Color,
blackBrush.Color,
new Duration(TimeSpan.FromMilliseconds(300)));
button.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, foregroundColorAnimation);
}
}
}
}
private static void ButtonOnMouseLeave(object sender, MouseEventArgs e)
{
if (sender is Button button &&
!(button.Parent is WindowCommands) &&
_initBackgroundBrush.ContainsKey(button) &&
_initForegroundBrush.ContainsKey(button))
{
var parentWindow = Window.GetWindow(button);
if (parentWindow != null)
{
if (parentWindow.Resources["AccentColorBrush"] is SolidColorBrush accentColorBrush &&
parentWindow.Resources["ForegroundForAccentedBrush"] is SolidColorBrush foregroundForAccentedBrush)
{
button.Background = new SolidColorBrush(((SolidColorBrush)button.Background).Color);
ColorAnimation backgroundColorAnimation = new ColorAnimation(
((SolidColorBrush)button.Background).Color,
_initBackgroundBrush[button],
new Duration(TimeSpan.FromMilliseconds(300)));
backgroundColorAnimation.Completed += (o, args) =>
{
if (_initBackgroundBrush[button] == accentColorBrush.Color)
button.SetResourceReference(Control.BackgroundProperty, "AccentColorBrush");
_initBackgroundBrush.Remove(button);
};
button.Background.BeginAnimation(SolidColorBrush.ColorProperty, backgroundColorAnimation);
button.Foreground = new SolidColorBrush(((SolidColorBrush)button.Foreground).Color);
ColorAnimation foregroundColorAnimation = new ColorAnimation(
((SolidColorBrush)button.Foreground).Color,
_initForegroundBrush[button],
new Duration(TimeSpan.FromMilliseconds(300)));
foregroundColorAnimation.Completed += (o, args) =>
{
if (_initForegroundBrush[button] == foregroundForAccentedBrush.Color)
button.SetResourceReference(Control.ForegroundProperty, "ForegroundForAccentedBrush");
_initForegroundBrush.Remove(button);
};
button.Foreground.BeginAnimation(SolidColorBrush.ColorProperty, foregroundColorAnimation);
}
}
}
}
}
}
我以按钮样式设置值:
<Style x:Key="ModPlusAccentButton" TargetType="{x:Type ButtonBase}">
<Setter Property="FocusVisualStyle" Value="{StaticResource FocusVisual}"/>
<Setter Property="Background" Value="{DynamicResource AccentColorBrush}" />
<Setter Property="BorderBrush" Value="{DynamicResource AccentColorBrush}" />
<Setter Property="Foreground" Value="{DynamicResource ForegroundForAccentedBrush}" />
<Setter Property="Padding" Value="12 6 12 6" />
<Setter Property="helpers:ButtonAssist.AnimateMouseOver" Value="True"></Setter>
<Setter Property="SnapsToDevicePixels" Value="True" />
.......
在调试中,我在ButtonOnMouseEnter方法中获得了正确的颜色。但是按钮的背景没有改变
但是,ButtonOnMouseLeave方法中的动画可以正常工作!
为什么呢?