【问题标题】:WPF 'Map' control; using canvas to display lots of bitmap imagesWPF“地图”控件;使用画布显示大量位图图像
【发布时间】:2012-07-03 00:21:27
【问题描述】:

我正在使用 Substrate 解析 minecraft 文件数据。 Minecraft 由“块”组成,“块”由块组成。所以我有一个带有不同 16x16 瓷砖的精灵表。我在 WPF 中使用croppedbitmap 来查找合适的图形平铺以构成地图的一部分。然后我在 WPF 中为“源”分配一个 Image() 控件,这是我的裁剪位图。最后,我执行 myCanvas.Children.Add(myImage)... 问题是,在我的画布中有大约 30 张左右的图像后,应用程序会慢下来。这是一个问题,因为典型的我的世界地图会有成百上千的图像。有没有更好的方法来绘制大量的位图数据?我喜欢拥有图像控件,因为这样我就可以在地图上放置工具提示并使其具有交互性。但我接受 Image 控件可能更昂贵,并且拥有数千个控件可能无法正常工作。这是我的代码。 (这只解析特定值的图块,因此如果 id == 9)

     var mapTiles = (BitmapImage)FindResource("mapTiles");
         CroppedBitmap waterImage = new CroppedBitmap(mapTiles, new Int32Rect(352, 48, 16, 16));
         CroppedBitmap grassImage = new CroppedBitmap(mapTiles, new Int32Rect(0, 0, 16, 16));
         foreach (ChunkRef chunk in chunkManager)
         {
             countOfTiles++;

             for (int x = 0; x <= 15; x++)
             {
                 for (int z = 0; z <= 15; z++)
                 {
                     int height = chunk.Blocks.GetHeight(x, z);
                     //TODO: Normalize Chunk X, Z so 0,0 is the smallest chunk so everything is visible on the canvas.
                     if (height > 0 && chunk.X > 0 && chunk.Z > 0)
                     {
                         var block = chunk.Blocks.GetBlock(x, height - 1, z);

                         if (block.ID == 9)
                         {
                             //352, 48
                             Image image = new Image();
                             image.Source = waterImage;
                             worldMap.Children.Add(image);
                             Canvas.SetTop(image, (chunk.X + x) * 16);
                             Canvas.SetLeft(image, (chunk.Z + z) * 16);
                             image.ToolTip = countOfTiles.ToString();
                         }

【问题讨论】:

    标签: c# wpf wpf-controls


    【解决方案1】:

    您可以使用 ImageBrush,而不是使用较重的 Image:

    // use ImageBrush's instead
    var waterImage = new ImageBrush(new CroppedBitmap(...));
    var grassImage = new ImageBrush(new CroppedBitmap(...));
    
    waterImage.Freeze();
    grassImage.Freeze();
    

    稍后:

    if (block.ID == 9)
    {
        var water = new Rectangle
        {
            Width = 16,
            Height = 16,
            Fill = waterImage
        };
        worldMap.Children.Add(water);
        Canvas.SetTop(water, (chunk.X + x) * 16);
        Canvas.SetLeft(water, (chunk.Z + z) * 16);
        water.ToolTip = countOfTiles.ToString();
    }
    

    如果我不使用 Freeze,我将无法让具有 100x100 磁贴世界的测试应用程序正确显示。当我冻结每个画笔时,我可以让地图无缝显示到大约 300x300。在 1000x1000 时它几乎不会加载,但此时您需要 consider virtualizing the view,因为 UI 无法优雅地处理那么多 UIElement。

    【讨论】:

    • 非常感谢!令人惊讶的是,这种方法最终速度快了多少。一个更正:我使用了“填充”而不是矩形上的“背景”属性。我认为这只是一个错字,因为我找不到背景属性。
    • 你是对的,这是一个错字。甚至可能值得设计一个轻量级的Control,它封装了一些块的子集。此外,您必须在 World Sizes 中的某个时间点移至虚拟化面板。
    • 我很好奇您所说的虚拟化视图是什么意思。你能提供一些链接或其他信息吗?再次感谢您的意见!
    • 基本上,它抽象出控件的子项,以便将较少数量的 UI 元素与不同的绑定数据重用,而不是数千个单独的 UI 元素。 A good series of articles from Dan Crevier covers making a virtualizing panel.
    猜你喜欢
    • 1970-01-01
    • 2017-02-18
    • 1970-01-01
    • 1970-01-01
    • 2018-01-16
    • 1970-01-01
    • 2014-11-06
    • 2011-05-18
    • 1970-01-01
    相关资源
    最近更新 更多