首页 > 解决方案 > 连续背景画笔动画

问题描述

每当鼠标悬停在我的用户控件上时,我都想制作一个连续的画笔动画。

我已经有了这个:

    private void MainControl_MouseEnter(object sender, MouseEventArgs e)
    {            
        BeginColorAnimation(Background, BackgroundHover);
    }

    private void BeginColorAnimation(Brush from, Brush to)
    {            
        BrushAnimation anim = new BrushAnimation()
        {
            From = from,
            To = to,
            Duration = AnimationDuration
        };
        
        BackgroundBorder.BeginAnimation(Border.BackgroundProperty, anim);                        
    }        

    private void MainControl_MouseLeave(object sender, MouseEventArgs e)
    {            
        BeginColorAnimation(BackgroundHover, Background);
    }

BrushAnimation 类可以在这里找到

我现在遇到的问题是,如果我将鼠标快速移到控件上,我的控件的背景会立即从背景画笔转移到 BackgroundHover 画笔(反之亦然),我不希望这样。

我怎样才能使它看起来像画笔之间的连续变化?

编辑 1

在这里你可以看到我遇到的问题的视频。

让我解释一下自己:

想象一下,我们有两把刷子,一把黑色,一把蓝色(或任何其他颜色)。当鼠标悬停在控件上时,我想将颜色的背景从黑色更改为蓝色,当鼠标退出控件时,我想将背景更改回黑色。那么如果鼠标悬停在控件上并在动画中途退出会发生什么?看起来好像是从一个画笔弹跳到另一个画笔。我想避免这种情况。

我尝试使用:

private void MainControl_MouseEnter(object sender, MouseEventArgs e)
{            
    BeginColorAnimation(BackgroundBorder.Background, BackgroundHover);
}

private void MainControl_MouseLeave(object sender, MouseEventArgs e)
{            
    BeginColorAnimation(BackgroundBorder.Background, Background);
}

但后来我收到:'System.InvalidOperationException' 这个freezable 不能被冻结。

编辑 2

最终使用 SolidColorBrush 而不是 Brush,并使用 ColorAnimation 类。

public bool BackgroundFrozen = true;

        private void MainControl_MouseEnter(object sender, MouseEventArgs e)
        {            
            BeginColorAnimation((SolidColorBrush)BackgroundBorder.Background, BackgroundHover);
        }

        private void BeginColorAnimation(SolidColorBrush from, SolidColorBrush to)
        {
            if(BackgroundFrozen)
            {
                BackgroundBorder.Background = BackgroundBorder.Background.CloneCurrentValue();
                BackgroundFrozen = false;
            }

            ColorAnimation anim = new ColorAnimation()
            {                
                From = from.Color,
                To = to.Color,
                Duration = AnimationDuration
            };
            
            BackgroundBorder.Background.BeginAnimation(SolidColorBrush.ColorProperty, anim);
        }        

        private void MainControl_MouseLeave(object sender, MouseEventArgs e)
        {            
            BeginColorAnimation((SolidColorBrush)BackgroundBorder.Background, Background);
        }

由于某种原因,Border Background 属性最初被冻结,所以我使用 BackgroundFrozen 布尔值在动画第一次运行时使用 CloneCurrentValue()“解冻”它。

结果在这里

标签: c#wpfanimationbrush

解决方案


阅读“编辑 2”,因为它是解决方案的一部分

正如某人所建议的那样,我删除From = from,并为动画制作了一个“动态”持续时间,同时考虑了fromend值。

结果:

start是原始值
end是目标值
actual是介于start和之间的东西end(可能相同)

private ColorAnimation GetColorAnimation(SolidColorBrush start, SolidColorBrush end, SolidColorBrush actual)
        {
            ColorAnimation anim = new ColorAnimation()
            {                
                To = end.Color,
                Duration = new Duration(TimeSpan.FromMilliseconds(GetAnimationDuration(start, end, actual)))
            };

            return anim;
        }

GetAnimationDuration返回一个double包含持续时间(以毫秒为单位)的

private double GetAnimationDuration(SolidColorBrush start, SolidColorBrush end, SolidColorBrush actual)
        {
            Color s = start.Color;
            Color e = end.Color;
            Color a = actual.Color;

            double Rdif = Math.Abs(s.R - e.R);
            double Gdif = Math.Abs(s.G - e.G);
            double Bdif = Math.Abs(s.B - e.B);            

            //Console.WriteLine("Rdif: {0}, Gdif: {1}, Bdif: {2}", Rdif, Gdif, Bdif);

            double Rp = Math.Abs(a.R - e.R) / Rdif;
            double Gp = Math.Abs(a.G - e.G) / Gdif;
            double Bp = Math.Abs(a.B - e.B) / Bdif;

            double p = 0;
            int c = 0;

            if(!double.IsNaN(Rp))
            {
                p += Rp;
                c += 1;
            }

            if (!double.IsNaN(Gp))
            {
                p += Gp;
                c += 1;
            }

            if (!double.IsNaN(Bp))
            {
                p += Bp;
                c += 1;
            }

            p /= c;

            //Console.WriteLine("Rp: {0}, Gp: {1}, Bp: {2}", Rp, Gp, Bp);

            double r = p * AnimationDuration;

            //Console.WriteLine("Result: {0}", r);

            return r;
        }

它是这样称呼的:

BackgroundBorder.Background.BeginAnimation(SolidColorBrush.ColorProperty, GetColorAnimation(startColor, endColor, (SolidColorBrush)BackgroundBorder.Background));

GetAnimationDuration()持续时间为 500 毫秒的测试结果

---------------------------
Mouse enter
---------------------------
R: 0, G: 0, B: 255
Rdif: 255, Gdif: 0, Bdif: 255
Rp: 1, Gp: NaN, Bp: 1
Result: 500
---------------------------
Mouse leave (after having passed half of the animation (approximately))
---------------------------
R: 193, G: 0, B: 182
Rdif: 255, Gdif: 0, Bdif: 255
Rp: 0,756862745098039, Gp: NaN, Bp: 0,286274509803922
Result: 260,78431372549

推荐阅读