WPF中BitmapSource创建速度非常慢的问题
我最近在做一个基于WPF的项目,其中有个功能是将一些几何图形数据绘制成为一张图片,然后再显示在界面上。
我尝试了两种方法:
1. 使用GDI+中的Bitmap和Graphics来绘制图片,再Save成Stream,再通过BitmapFrame.Create来将创建BitmapSource,最后通过Image控件呈现图片。
2. 使用WPF中的DrawingVisual绘制图形,并使用RenderTargetBitmap生成BitmapSource,最后通过Image控件呈现图片。
其实,如上两种方法,本质上都是先绘制图形,再构造成WPF的Image控件支持的BitmapSource。只是前一种使用的是GDI+的绘制,后一种使用的是WPF的绘制。
如上两种方法在正常情况下工作都很正常,但是,如果当该应用程序的内存占用达到1.5G以上时(我会把所有数据加载到内存中),如上所述的两个方法中的第二个阶段,也就是构造BitmapSource的过程,会变得非常慢,会耗时1s以上,而正常情况下只耗时20毫秒。
经过反复测试,我发现耗时问题这只跟程序的内存占用有关系,内存一旦达到1.5G左右或以上,BitmapSource的构造就会很慢,内存一减下来,就又恢复正常速度。
为了避免多余的代码干扰,我特地建立一个新的测试项目,发现该问题仍然存在,测试代码如下:
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Timers;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SampleGDI
{
class Geo
{
public string GeoText { get; set; }
}
public partial class MainWindow : Window
{
private Random rd = new Random((int)DateTime.Now.Ticks);
private Timer timer = new Timer(1000);
//用于存放大数据
private List<object> data = new List<object>(200000000);
public MainWindow()
{
InitializeComponent();
//模拟大数据量的内存占用
for (int i = 0; i < 40000000; i++)
data.Add(new Geo() { GeoText = "POLYGON ((1 1, 1 2, 2 2, 2 1, 1 1))" });
timer.Elapsed += timer_Elapsed;
timer.Start();
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Draw();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
}
private void Draw()
{
timer.Stop();
while (true)
{
var sw = System.Diagnostics.Stopwatch.StartNew();
var visual = new DrawingGroup();
using (var context = visual.Append())
for (int i = 0; i < 10; i++)
context.DrawEllipse(Brushes.Black, new Pen(Brushes.Black, 1), new Point(rd.Next(800), rd.Next(480)), 4, 4);
sw.Stop();
var v = new DrawingVisual();
using (var context = v.RenderOpen())
context.DrawDrawing(visual);
sw.Stop();
Console.WriteLine("绘制:{0}", sw.Elapsed);
System.Threading.Thread.Sleep(1000);
sw = System.Diagnostics.Stopwatch.StartNew();
var dImageSource = new RenderTargetBitmap(800, 480, 96, 96, System.Windows.Media.PixelFormats.Pbgra32);
dImageSource.Render(v); // 这一步很慢,会耗时1s左右,正常情况只耗时20毫秒左右。
dImageSource.Freeze();
sw.Stop();
Console.WriteLine("构造:{0}", sw.Elapsed);
System.Threading.Thread.Sleep(1000);
sw = System.Diagnostics.Stopwatch.StartNew();
Dispatcher.Invoke(new Action(() => { image.Source = dImageSource; }));
sw.Stop();
Console.WriteLine("显示:{0}\r\n", sw.Elapsed);
System.Threading.Thread.Sleep(2000);
}
}
}
}
请问,如果在不修改数据读取机制(全部加载到内存这种方式)的情况下,应该怎样解决速度慢的问题?