我目前正在为Ising模型(德语维基百科,因为只有右边的图片才是真正重要的)开发一个GUI,该模型应该由大约200x200个旋转元素组成。我通过以下方式实现了这一点:
<UniformGrid Name="grid" .... />
并为代码中的每个旋转添加了一个矩形,如果旋转的值发生变化,我会更新该矩形。不知怎么的,这很慢,我改变了它,所以它使用绑定
<ItemsControl Name="IsingLattice" ItemsSource="{Binding Spins}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<UniformGrid Name="grid" ...
...
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<Rectangle Fill={Binding Color} ...
但这又非常缓慢。我试着调试和改进了3天,但到目前为止没有成功。
现在的问题是:我的方法错了吗?如果是,我应该使用什么?如果没有,我该如何提高性能?
如果它是相关的,我将更新这篇文章与我的模型实现的一些细节。
编辑:应该可以通过与元素交互来更改单个旋转。这可以在实际图形的顶部使用透明层来完成,但无论如何可能都没那么难。
您可以编写一个自定义元素(从FrameworkElement
派生),在内部存储自旋数据,然后通过重写OnRender
方法一次性渲染数据:
public sealed class IsingModel : FrameworkElement
{
readonly bool[] _spinData = new bool[200 * 200];
protected override void OnRender(DrawingContext dc)
{
// use methods of DrawingContext to draw appropriate
// filled squares based on stored spin data
}
protected override void OnMouseDown(MouseButtonEventArgs e)
{
base.OnMouseDown(e);
// work out which "cell" was clicked on and change
// appropriate spin state value in Boolean array
InvalidateVisual(); // force OnRender() call
}
}
这种方法应该比拥有几千个单独的元素更快。我不知道要快多少。
这似乎是一个位图,所以你应该威胁它作为位图。使用Image代替ItemsControl,使用WritableBitmap代替ItemsSource作为图像源。
当涉及到原始代码时,它可能会有几个性能瓶颈:
- 生成用作ItemsSource的类可能需要一些时间
- UniformGrid需要测量每个元素的大小并计算其位置。这可能需要一段时间。使用Canvas可以获得更好的效果
- ItemsControl从DataTemplate生成40000个项目可能需要一些时间。您可以手动创建这些矩形,并在代码后面将其添加到画布中
- 绑定具有性能成本。如果您的每个项目都是数据绑定的,那么您的绑定需要评估40000次。您可以在代码隐藏中手动设置属性,而不是绑定
使用画布和无绑定,我能够在500毫秒内渲染网格。然而,使用WritableBitmap或其他"基于像素"的方法,可以显示更大的网格。
GUI,任何类型的GUI技术,无论是WPF、Windows窗体还是其他任何技术,都不意味着要处理繁重的图形。这意味着开发简单的图形很容易。
如果你需要图形能力(比如动态更新40.000个单元格),那么你需要一个图形框架。最有可能的是,一个游戏框架就可以了,从你的选择中选择一个。
或者,你可以尝试自己模仿它,只绑定到一张图片上,并在细胞发生变化时自己绘制该图片。也许这就足够了,你必须测试一下。
您是否考虑过使用BitmapCache来提高渲染速度?
我的理解是,在绘制复杂控件时,或者在屏幕上同时显示多个控件实例时,这可以显著提高渲染速度。您可能希望在网格级别启用缓存,而不是在每个单独的微调器上启用缓存。