C# 如何释放以编程方式创建的ColorAnimation和Storyboard对象
实现逻辑说明
.NET 中 Storyboard、ColorAnimation 都属于托管对象,本身不提供手动释放的接口,完全由 GC(垃圾回收器)负责回收,只要切断所有根引用,GC 会在合适的时机自动回收对应的内存。
现有释放逻辑的优化
你原来的代码中仅调用 Stop() 还不够,需要额外切断所有引用链,才能确保对象可以被GC回收,注释处的代码可以补充为:
GridItemAnimationStoryBoard.Stop(); // 清除动画的目标绑定,切断动画对UI元素的引用 Storyboard.SetTarget(GridItemColorAnimation, null); // 从情节提要中移除动画 GridItemAnimationStoryBoard.Children.Clear(); // 全局变量置空,切断根引用 GridItemColorAnimation = null; GridItemAnimationStoryBoard = null;
额外优化建议
- 监听动画完成事件自动清理
可以给Storyboard绑定Completed事件,动画执行结束后自动执行清理逻辑,不需要等到下次点击才清理上一次的对象:
GridItemAnimationStoryBoard.Completed += (s, e) => { var sb = s as Storyboard; sb.Stop(); foreach (var anim in sb.Children) { Storyboard.SetTarget(anim, null); } sb.Children.Clear(); // 如果你用列表存了所有Storyboard,在这里移除对应实例即可 };
- 复用动画对象(更推荐)
不需要每次点击都新建动画和Storyboard实例,只要重置目标、属性值就可以复用,减少GC压力:
// 全局只初始化一次 if (GridItemAnimationStoryBoard == null) { GridItemColorAnimation = new ColorAnimation(); GridItemAnimationStoryBoard = new Storyboard(); GridItemColorAnimation.EnableDependentAnimation = true; GridItemAnimationStoryBoard.Children.Add(GridItemColorAnimation); Storyboard.SetTargetProperty(GridItemColorAnimation, "Color"); } // 每次点击只修改动态属性 GridItemAnimationStoryBoard.Stop(); var duration = new Duration(TimeSpan.FromMilliseconds(employees_data_model.selected_employee_contact.DeleteEmployee == true ? 300 : 1000)); GridItemColorAnimation.Duration = duration; GridItemAnimationStoryBoard.Duration = duration; Storyboard.SetTarget(GridItemColorAnimation, GridItem.Background); GridItemColorAnimation.To = employees_data_model.selected_employee_contact.DeleteEmployee == true ? ColorHelper.FromArgb(150, 255, 100, 100) : ColorHelper.FromArgb(0, 0, 0, 0); GridItemAnimationStoryBoard.Begin();
- 注意ListView虚拟化适配
如果你的ListView开启了虚拟化,条目滑出可视区域时会被系统回收,此时如果动画还在执行,要提前停止并清理对应动画的目标绑定,避免出现内存泄漏。
现有方案的合理性
你当前采用的Stop()+清空存储列表的方案已经符合GC回收要求,只要没有其他静态变量、全局事件持有这些Storyboard的引用,就不会出现内存泄漏。非特殊情况不建议手动调用GC.Collect(),频繁触发垃圾回收反而会降低应用运行性能。
内容的提问来源于stack exchange,提问作者Eugen M
相关产品推荐
相关产品推荐

