连续背景刷动画
Continuous background brush animation
我想在鼠标悬停在我的用户控件上时制作一个连续的笔刷动画。
我已经有了这个:
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 class here
我现在遇到的问题是,如果我将鼠标快速移到控件上,控件的背景会立即从背景画笔切换到 BackgroundHover 画笔(反之亦然),我不希望这样。
我怎样才能让它看起来像笔刷之间的连续变化?
编辑 1
Here你可以看到我遇到的问题的视频。
让我解释一下:
假设我们有两把刷子,一把黑色,一把蓝色(或任何其他颜色)。当鼠标悬停在控件上时,我想将颜色背景从黑色更改为蓝色,当鼠标离开控件时,我想将背景颜色更改回黑色。
那么如果鼠标悬停在控件上并在动画中途退出会怎样呢?看起来好像是从一个画笔跳到另一个画笔。我想避免这种情况。
我尝试使用:
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 class。
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);
}
出于某种原因,边框背景 属性 一开始是冻结的,所以当动画第一次运行时,我使用 BackgroundFrozen 布尔值通过 CloneCurrentValue() 来“解冻”它。
结果here
阅读“编辑 2”,因为它是解决方案的一部分
根据某人的建议,我删除了 From = from,
并为动画制作了一个“动态”持续时间,同时考虑了 from
和 end
值。
结果:
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
returns 包含以毫秒为单位的持续时间的 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
我想在鼠标悬停在我的用户控件上时制作一个连续的笔刷动画。
我已经有了这个:
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 class here
我现在遇到的问题是,如果我将鼠标快速移到控件上,控件的背景会立即从背景画笔切换到 BackgroundHover 画笔(反之亦然),我不希望这样。
我怎样才能让它看起来像笔刷之间的连续变化?
编辑 1
Here你可以看到我遇到的问题的视频。
让我解释一下:
假设我们有两把刷子,一把黑色,一把蓝色(或任何其他颜色)。当鼠标悬停在控件上时,我想将颜色背景从黑色更改为蓝色,当鼠标离开控件时,我想将背景颜色更改回黑色。 那么如果鼠标悬停在控件上并在动画中途退出会怎样呢?看起来好像是从一个画笔跳到另一个画笔。我想避免这种情况。
我尝试使用:
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 class。
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);
}
出于某种原因,边框背景 属性 一开始是冻结的,所以当动画第一次运行时,我使用 BackgroundFrozen 布尔值通过 CloneCurrentValue() 来“解冻”它。
结果here
阅读“编辑 2”,因为它是解决方案的一部分
根据某人的建议,我删除了 From = from,
并为动画制作了一个“动态”持续时间,同时考虑了 from
和 end
值。
结果:
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
returns 包含以毫秒为单位的持续时间的 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