为啥从组合框进行选择后切换图形需要更长的时间?

Posted

技术标签:

【中文标题】为啥从组合框进行选择后切换图形需要更长的时间?【英文标题】:Why does it take longer to toggle graphics after a selection is made from a combo box?为什么从组合框进行选择后切换图形需要更长的时间? 【发布时间】:2012-04-12 07:21:16 【问题描述】:

我有一个绘制指南针的 WPF 应用程序。有一个带有刻度线和标签的大环。我有一个复选框,可以打开和关闭罗盘图形。当我第一次启动应用程序时,指南针会立即打开和关闭。

同时,我有一个组合框,它从本地数据库中获取一些数据并使用它来呈现一些叠加图形。使用此组合框后,指南针图形不再快速切换。事实上,每当我单击复选框时,UI 都会完全冻结大约 4 秒。

我尝试使用 WPF 的 Window Performance Profiling Tool 来分析我的应用程序。当我激活该复选框时,不仅我的应用程序冻结了,分析器也冻结了。之后图表“赶上了”,但这告诉我一定有严重错误。

我已经设法确定问题图形是刻度线(而不是数字标签)。如果我消除它们,冻结问题就会停止。如果我将它们从 360 减少到 36,应用程序仍然会冻结,但时间会更短。同样,无论我有多少刻度线,它们都会在应用首次启动时立即切换。

我的问题是,我如何弄清楚为什么我的指南针图形的切换从即时变为非常慢?我已经尝试了广泛的分析和调试,但我就是想不出来有任何理由为什么在某些刻度线上设置可见性会导致应用程序冻结。

编辑

好的,我已经从我的应用程序中剥离了所有内容,只剩下最基本的部分,将其压缩,然后上传到 Sendspace。这是链接(大约 143K):

http://www.sendspace.com/file/n1u3yg

[注意:不要不小心点击了横幅广告,真正的下载链接在页面上要小得多。]

两个请求:

    您的计算机上是否遇到过问题? 尝试打开 Compass.exe(在 bin\Release 中)并快速单击复选框。指南针刻度线应无延迟地打开和关闭。然后,从组合框中选择一个项目并尝试再次快速单击该复选框。在我的机器上,它非常滞后,在我停止快速点击后,图形需要几秒钟才能赶上。

    如果您确实遇到了延迟,您是否在代码中看到任何可能导致这种奇怪行为的内容? 组合框未连接到任何东西,那么为什么要选择一个项目是否会影响窗口上其他图形的未来性能?

【问题讨论】:

我认为如果你想要一个答案,你应该上传代码 但您没有找到性能瓶颈吗? @Tigran,只是有点。我知道刻度线是瓶颈,但我不知道为什么它们有时不是瓶颈。我想弄清楚是什么条件导致它们成为问题。 另外,当我隐藏它们时冻结和显示它们时一样糟糕。 当你有一个无限循环,或者一个运行时间太长的时候,只需在 IDE 中暂停一次,看看它在做什么,因为你知道它在循环中。 【参考方案1】:

虽然 ANTS 没有指出特定的性能“热点”,但我认为您的技术存在轻微缺陷,因为似乎每个刻度都有一个 ViewModel 负责处理单个刻度,并且您正在单独绑定这些滴答作响。您最终会为这些刻度创建 720 个视图模型,每次显示或隐藏整个指南针时都会触发类似的事件。每次访问此字段时,您还会创建一个新的 LineGeometry。

在这样的自定义绘制情况下,推荐的 WPF 方法是使用 DrawingVisual 并采用 WPF 呈现系统的保留模式方面。有几个 googleable 资源讨论了这种技术,但要点是声明一个从 FrameworkElement 继承的指南针类,以及从 DrawingVisual 继承的一些较小的类,并使用它来渲染指南针。使用这种技术,您仍然可以让 ViewModel 驱动指南针行为,但您不会为指南针的每个部分提供单独的视图模型。我倾向于将指南针分解成挡板、箭头、瞄准器等部分……但您的问题可能需要采用不同的方法。

class Compass : FrameworkElement

    private readonly List<ICompassPart> _children = new List<ICompassPart>();

    public void AddVisualChild(ICompassPart currentObject)
    
        _children.Add(currentObject);
        AddVisualChild((Visual)currentObject);
    

    override protected int VisualChildrenCount  get  return _children.Count;  

    override protected Visual GetVisualChild(int index)
    
        if (index < 0 || index >= _children.Count) throw new ArgumentOutOfRangeException();

        return _children[index] as Visual;
    

    override protected void OnRender(DrawingContext dc)
    
        //The control automatically renders its children based on their RenderContext.
        //There's really nothing to do here.
        dc.DrawRectangle(Background, null, new Rect(RenderSize));
    


class Bezel : DrawingVisual

   private bool _visible;

   public bool Visible 
   
     get  return _visible; 
     set
     
        _visible = value;
        Update();
     
   

   private void Update()
   
       var dc = this.RenderOpen().DrawingContext;
       dc.DrawLine(/*blah*/);
       dc.Close();
   

【讨论】:

嗨里奇。 +1,感谢您花时间查看我的代码示例并写下您的答案。我确实有几个问题/cmets。首先,我似乎只创建了 360 视图模型,而不是 720。至少,我已经验证了构造函数只被调用了 360 次。你能解释一下你在哪里看到 720 视图模型吗?其次,我认为我不是每次都创建新的线条几何图形,而只是在第一次绘制刻度时。事实上,如果我在 public Geometry Geometry 属性 getter 中设置一个断点,它只会在应用程序的整个生命周期内被命中一次。 (续)最后,虽然您的回答很可能完全绕过了我遇到的问题,但它并没有直接回答我的问题,即:您是否体验过减速仅 从下拉列表中选择一个项目后,如果是,为什么?即使我应该使用 VisualHost 和 DrawingVisual(我肯定会考虑切换到这种技术),为什么只有在操作看似无关的组合框后性能才会变慢? 跟进:我只是尝试保持代码不变,除了切换整个 CompassLayer 而不是单个刻度线。这似乎消除了使用组合框后任何明显的延迟。但是,我仍然无法解释组合框的作用。 最后一项:我似乎在 MSDN 上找不到 VisualHost 类的任何文档。这绝对是班级的名字吗? @DanM - 对于 720 调用,在 Geometry 属性上放置一个 Debug.Trace 行和一个静态计数器(这是我提到的重复创建,除非你需要这样做,否则显然不要缓存,但这似乎是其中一种情况[如果你坚持使用这种技术])。我先在 ANTS 中看到它,然后我通过追踪来测量它。我看不出这两种情况之间的性能差异。

以上是关于为啥从组合框进行选择后切换图形需要更长的时间?的主要内容,如果未能解决你的问题,请参考以下文章

为啥从 Spark 写入 Vertica DB 比从 Spark 写入 MySQL 需要更长的时间?

为啥一个循环比另一个循环检测共享内存更新需要更长的时间?

如何根据从另一个组合框进行的选择来填充组合框

当我包含验证数据时,为啥模型训练需要更长的时间?

根据组合框选择切换表单上其他字段的可见性 - MS Access

如何动态更改组合框显示成员