【发布时间】:2011-08-05 19:22:11
【问题描述】:
我正在尝试使用 WPF 绘制图像/图标网格。网格尺寸会有所不同,但通常范围为 10x10 到 200x200。用户应该能够点击单元格,有些单元格需要每秒更新(更改图像)10-20 次。网格应该能够在所有四个方向上增长和缩小,并且应该能够切换到它所代表的 3D 结构的不同“切片”。我的目标是根据这些要求找到一种适当有效的方法来绘制网格。
我当前的实现使用 WPF Grid。我在运行时生成行和列定义,并用Line(用于网格线)和Border(用于单元格,因为它们当前只是开/关)对象在适当的行/列填充网格。 (Line 对象一直跨越。)
在扩展网格时(按住 Num6),我发现它的绘制速度太慢,无法重绘每个操作,因此我对其进行了修改,只为每个操作添加了一个新的 ColumnDefinition、Line 和一组 Border 对象成长的柱子。这解决了我的增长问题,并且可以使用类似的策略来快速收缩。为了在模拟过程中更新单个单元格,我可以简单地存储对单元格对象的引用并更改显示的图像。甚至可以通过仅更新单元格内容而不是重建整个网格来改进到新的 Z 级别。
但是,在进行所有这些优化之前,我遇到了另一个问题。每当我将鼠标悬停在网格上时(即使是低速/正常速度),应用程序的 CPU 使用率都会飙升。我从网格的子元素中删除了所有事件处理程序,但这没有任何效果。最后,控制 CPU 使用率的唯一方法是将IsHitTestVisible = false 设置为Grid。 (为Grid 的每个子元素设置这个没有任何作用!)
我认为使用单独的控件来构建我的网格过于密集且不适合此应用程序,并且使用 WPF 的 2D 绘图机制可能更有效。不过,我是 WPF 的初学者,所以我正在寻求如何最好地实现这一目标的建议。根据我所阅读的内容,我可能会使用DrawingGroup 将每个单元格的图像组合到一个图像中以供显示。然后我可以对整个图像使用单击事件处理程序,并通过鼠标位置计算单击单元格的坐标。不过,这似乎很乱,我只是不知道是否有更好的方法。
想法?
更新 1:
我听取了朋友的建议,转而使用Canvas 和Rectangle 为每个单元格。当我第一次绘制网格时,我将所有Rectangle 的引用存储在一个二维数组中,然后当我更新网格内容时,我只需访问这些引用。
private void UpdateGrid()
{
for (int x = simGrid.Bounds.Lower.X; x <= simGrid.Bounds.Upper.X; x++)
{
for (int y = simGrid.Bounds.Lower.Y; y <= simGrid.Bounds.Upper.Y; y++)
{
CellRectangles[x, y].Fill = simGrid[x, y, ZLevel] ? Brushes.Yellow : Brushes.White;
}
}
}
最初绘制网格似乎更快,后续更新肯定更快,但仍然存在一些问题。
无论我将鼠标悬停的区域有多小,当我将鼠标悬停在具有数百个单元格的网格上时,CPU 使用率仍然会达到峰值。
更新仍然太慢,所以当我按住向上箭头键更改 Z 级别(常见用例)时,程序一次冻结几秒钟,然后似乎跳了 50 个 Z 级别一次。
一旦网格包含约 5000 个单元格,更新时间大约为一秒。这非常慢,5000 个单元适合典型用例。
我还没有尝试过UniformGrid 方法,因为我认为它可能会出现我已经遇到过的相同问题。不过,一旦我用尽了更多选项,我可能会尝试一下。
【问题讨论】:
-
您是否在 Canvas 上尝试过 IsHitTestVisible = false 在您的新方法中以控制鼠标悬停时的 CPU 使用?
-
您是否显示具有动态缩放级别的地图?