C# 绘制平铺设置图形以在绘制事件运行缓慢时显示屏幕

C# 绘制平铺设置图形以在绘制事件运行缓慢时显示屏幕,c#,performance,graphics,onpaint,C#,Performance,Graphics,Onpaint,正如您可以从下面的代码中看出的,我对C非常陌生。对于我的第一个测试项目,我制作了一个2D级别编辑器,它有5层。在下面的代码中,我希望通过一个短名单字典进行教学,该字典在地图每次更改时生成,并且只包含填充的瓷砖,而不是使用forx fory for zdraw图形,它必须检查网格的每个部分是否有任何内容 它运行良好,直到我在屏幕上有大约30个瓷砖,然后它开始运行非常缓慢,就像真的很不稳定。此绘制事件仅在需要时调用,它不在计时器上运行,它仅在铺设新瓷砖或鼠标光标悬停在新块上时运行。所以我猜问题在于图

正如您可以从下面的代码中看出的,我对C非常陌生。对于我的第一个测试项目,我制作了一个2D级别编辑器,它有5层。在下面的代码中,我希望通过一个短名单字典进行教学,该字典在地图每次更改时生成,并且只包含填充的瓷砖,而不是使用forx fory for zdraw图形,它必须检查网格的每个部分是否有任何内容

它运行良好,直到我在屏幕上有大约30个瓷砖,然后它开始运行非常缓慢,就像真的很不稳定。此绘制事件仅在需要时调用,它不在计时器上运行,它仅在铺设新瓷砖或鼠标光标悬停在新块上时运行。所以我猜问题在于图像被绘制到屏幕上的部分,就像一些东西正在积累很多

DrawImage函数下面注释掉的那行代码是为了测试仅仅绘制矩形而不是tileset的一部分是否更快。而且是!!我很抱歉我可能听起来像努比,但请记住,这是我的第一个项目,不确定在哪里可以找到关于这个特定主题的答案

谢谢!,下面是我的绘画代码

public void editor_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = e.Graphics;
        string[] keys;
        string[] values;

        foreach(KeyValuePair<string, string> dict in map.shortlist){
            keys = dict.Key.Split('|');
            values = dict.Value.Split('|');
            int xpos = Convert.ToInt16(keys[0]);
            int ypos = Convert.ToInt16(keys[1]);
            int zpos = Convert.ToInt16(keys[2]);

            Tile tile = map.data[xpos, ypos, zpos];
            if (tile.type == "tile")
            {
                Bitmap img = tileset.bitmap.Clone(new Rectangle(tile.x * 16, tile.y * 16, 16, 16), tileset.bitmap.PixelFormat);
                g.DrawImage(img, new Point(xpos * 16, ypos * 16));                                       
                //g.DrawRectangle(Pens.Blue, new Rectangle(new Point(xpos * 16, ypos * 16), new Size(16,16)));                                       
            }
        }

        if (selector.MouseOver == true)
        {
            int tileSize = Preferences.blockSize;                
            Pen pen = new Pen(Color.Red, 1);                
            g.DrawRectangle(pen, new Rectangle(new Point((MouseX / tileSize) * tileSize, (MouseY / tileSize) * tileSize), new Size(tileSize, tileSize)));
        }
    }

为了防止有人有类似的性能问题,我将以一种迂回的方式回答这个问题,感谢下面评论中的人向我指出了一些问题

导致问题的原因很可能非常明显:

Bitmap img = tileset.bitmap.Clone(new Rectangle(tile.x * 16, tile.y * 16, 16, 16), tileset.bitmap.PixelFormat);
它必须在每个foreach上创建一个新位图,当它遇到一个平铺时,从原始平铺集位图中选择一个正方形。这样做30-40次是相当劳动密集的

因此,我只是在第一次加载tileset时将所有Tile缓存到一个数组中,如下所示:

    private void GenerateBitmapTiles() {
        Bitmap bitmap = new Bitmap(TilesetImageFile);

        bitmaps = new Bitmap[image.Width / 16, image.Height / 16];
        for (int x = 0; x < image.Width / 16; x++)
        {
            for (int y = 0; y < image.Height / 16; y++)
            {
                bitmaps[x, y] = bitmap.Clone(new Rectangle(x * 16, y * 16, 16, 16), bitmap.PixelFormat);
            }
        }

        bitmap.Dispose();
    }
但是!在阅读了下面的评论后,我意识到winforms是一种较旧的技术。。Winforms并没有过时,但WPF是一种较新的技术,在压力下可以表现得更好,加上它的硬件加速


我已经开始在WPF中重建项目,而绘画并不是一个问题。而不是说:这是我的数据,现在每次屏幕绘制时,我想在这里和这里画这个对象,在WPF中,你只需要说,我想在这里和这里画我的对象。其余部分由WPF自己完成。

只是一个建议,一个建议:如果你要花时间学习C和.Net,我强烈建议你不要使用winforms,而是学习任何基于XAML的技术。当涉及到图形时,winforms与WPF相比是非常无用的。而且,它没有硬件加速,因此存在这些性能问题,您现在正在试验。在WPF中,你甚至不需要处理你在这里写的东西。没有tile.x、tile.y、16、16、16等,因为任何东西都可以拉伸到容器的大小。另外,WinRT的新技术都是基于XAML的。@HighCore您在某种程度上是对的,但并非完全正确。Windows窗体是用于桌面业务应用程序的成熟技术。除了grahics和facy动画之外,大多数情况下WPF不适合LOB应用程序。另外,学习Windows窗体也更容易。谢谢你们的回复。最后,我将tileset中的所有tile保存到一个数组中,这样就不必在每次迭代时都将它们取出,从而对问题进行了排序。现在真的很快!那么使用WPF的结论是什么?我什么时候应该使用Windows窗体,什么时候应该使用WPF?@MD.Unicorn对不起,我完全不同意。WPF提供了一个严肃的绑定框架,并允许诸如MVVM之类的东西,这些东西比现有的任何东西都更适合LOB。在WPF中编写具有高级功能的CRUD屏幕和数据网格与在winforms中执行任何有用的操作所需的多种黑客相比,是干净和不错的。WPF不仅仅是关于你所说的奇特的图形,它还涉及到视图和逻辑的分离,而winforms是无法做到的。WPF具有更好的性能和内置的UI虚拟化,因此在处理大型应用程序时速度更快collections@MD.Unicorn请继续向我展示一个winforms比WPF更适合的用例。此外,WPF4.0与winforms一样成熟。学习曲线当然更陡峭,但最终WPF更简单,因为在MVVM中,您几乎从不在代码中操作UI元素。
g.DrawImage(bitmap[x, y], new Point(xpos * 16, ypos * 16));