更新元素时的WPF性能



我目前正在为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
    }
}

这种方法应该比拥有几千个单独的元素更快。我不知道要快多少。

ItemsControl旨在重复基于数据源的UI控件。UI控件必须是可自定义的,在布局更改时响应,并且是交互式的。这两者都不是你的情况。您实际上只想渲染一张图片。

这似乎是一个位图,所以你应该威胁它作为位图。使用Image代替ItemsControl,使用WritableBitmap代替ItemsSource作为图像源。

当涉及到原始代码时,它可能会有几个性能瓶颈:

  1. 生成用作ItemsSource的类可能需要一些时间
  2. UniformGrid需要测量每个元素的大小并计算其位置。这可能需要一段时间。使用Canvas可以获得更好的效果
  3. ItemsControl从DataTemplate生成40000个项目可能需要一些时间。您可以手动创建这些矩形,并在代码后面将其添加到画布中
  4. 绑定具有性能成本。如果您的每个项目都是数据绑定的,那么您的绑定需要评估40000次。您可以在代码隐藏中手动设置属性,而不是绑定

使用画布和无绑定,我能够在500毫秒内渲染网格。然而,使用WritableBitmap或其他"基于像素"的方法,可以显示更大的网格。

GUI,任何类型的GUI技术,无论是WPF、Windows窗体还是其他任何技术,都不意味着要处理繁重的图形。这意味着开发简单的图形很容易。

如果你需要图形能力(比如动态更新40.000个单元格),那么你需要一个图形框架。最有可能的是,一个游戏框架就可以了,从你的选择中选择一个。

或者,你可以尝试自己模仿它,只绑定到一张图片上,并在细胞发生变化时自己绘制该图片。也许这就足够了,你必须测试一下。

您是否考虑过使用BitmapCache来提高渲染速度?

我的理解是,在绘制复杂控件时,或者在屏幕上同时显示多个控件实例时,这可以显著提高渲染速度。您可能希望在网格级别启用缓存,而不是在每个单独的微调器上启用缓存。

最新更新