我们必须在WPF应用程序中显示一个合法的弹出窗口。当弹出窗口显示时,我们对下面的视图使用模糊效果。
最近我们意识到这会导致高GPU使用率。因为后台的旋转控件。活动内容越多,GPU使用量越大。
当弹出窗口基于属性显示时,我们折叠这个旋转控件。但这无济于事。只有当我们在主窗口中将其设置为折叠时。
我们尝试了很多东西,例如BitmapCache和其他技术,但到目前为止还没有成功。
这里有一个例子:https://github.com/rmoergeli/BlurEffectTest.git
我调查了演示代码中的问题隐藏在你的动画中:它不会停止从visible
到collapsed
的可见性。
所以我找到了一个解决方案,在MSDN资源的帮助下停止动画被折叠。
public partial class Spinner : UserControl
{
private Canvas _content;
private Storyboard _rotationStoryboard;
public Spinner()
{
// Create a name scope for the page.
NameScope.SetNameScope(this, new NameScope());
DefineContent();
SizeChanged += Spinner_SizeChanged;
IsVisibleChanged += Spinner_IsVisibleChanged;
Loaded += Spinner_Loaded;
}
private void Spinner_Loaded(object sender, RoutedEventArgs e)
{
_rotationStoryboard.Begin(this, isControllable: true);
}
private void Spinner_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue is bool isVisible && isVisible)
_rotationStoryboard.Resume(this);
else
_rotationStoryboard.Pause(this);
}
private void DefineContent()
{
_content = new Canvas();
//set content render transform origin point to center
_content.RenderTransformOrigin = new Point(0.5 , 0.5);
_content.RenderTransform = new RotateTransform(angle: 0);
// Assign the canvas a name by
// registering it with the page, so that
// it can be targeted by storyboard
// animations.
RegisterName("animatableCanvas", _content);
Content = _content;
DefineAnimatableContent();
// Create an animation and a storyboard to animate the
// canvas.
DoubleAnimation doubleAnimation = new DoubleAnimation
{
To = 360,
Duration = new Duration(TimeSpan.FromSeconds(3)),
RepeatBehavior = RepeatBehavior.Forever
};
Storyboard.SetTargetName(doubleAnimation, "animatableCanvas");
Storyboard.SetTargetProperty(doubleAnimation, new PropertyPath("RenderTransform.Angle"));
_rotationStoryboard = new Storyboard();
_rotationStoryboard.Children.Add(doubleAnimation);
}
private void DefineAnimatableContent() //renamed Refresh method
{
int n = Balls;
double size = BallSize;
_content.Children.Clear();
double x = ActualWidth / 2;
double y = ActualHeight / 2;
double r = Math.Min(x, y) - size / 2;
double doubleN = Convert.ToDouble(n);
for (int i = 1; i <= n; i++)
{
double doubleI = Convert.ToDouble(i);
double x1 = x + Math.Cos(doubleI / doubleN * 2d * Math.PI) * r - size / 2;
double y1 = y + Math.Sin(doubleI / doubleN * 2d * Math.PI) * r - size / 2;
var e = new Ellipse
{
Fill = BallBrush,
Opacity = doubleI / doubleN,
Height = size,
Width = size
};
Canvas.SetLeft(e, x1);
Canvas.SetTop(e, y1);
_content.Children.Add(e);
};
}
#region Event Handlers
private void Spinner_SizeChanged(object sender, SizeChangedEventArgs e)
{
//we dont need this anymore as we set content render transform origin point to content center
//Transform.CenterX = ActualWidth / 2;
//Transform.CenterY = ActualHeight / 2;
DefineAnimatableContent();
}
#endregion
//other logic
}
此代码在改变Spiner
控件可见性时停止动画。但是你可以用任何你需要的触发器来暂停和恢复动画。
注意!使用这种方法,您可以在代码中定义所有内容(不仅仅是可动画的部分),因此您不再需要Spinner.xaml
资源。