c# - WPF Canvas 在大量绘制时冻结
问题描述
我是初学者,正在做一些 C# 练习。我发现了 Forest Fire Model 并尝试使用 WPF 和绘图来做到这一点,我通过为每个像素创建一个矩形来使用画布。我遇到的问题是程序冻结并且画布不绘制任何东西(使用 while(true) 循环)。此外,我在迭代后删除了所有子项,但程序仍在收集 GB 的 RAM。
用于测试的简化代码:
public partial class TestDrawing : Window
{
public TestDrawing()
{
InitializeComponent();
}
private void btnStart_Click(object sender, RoutedEventArgs e)
{
DrawForestFire();
}
private void DrawForestFire()
{
Random rand = new Random();
while (true)
{
for (int y = 0; y < 100; y++)
{
for (int x = 0; x < 100; x++)
{
Rectangle rectangle = new Rectangle();
Color color = Color.FromRgb((byte)rand.Next(200),
(byte)rand.Next(200), (byte)rand.Next(200));
rectangle.Fill = new SolidColorBrush(color);
rectangle.Width = 4;
rectangle.Height = 4;
Canvas.SetTop(rectangle, y * 4);
Canvas.SetLeft(rectangle, x * 4);
canvas.Children.Add(rectangle);
}
}
canvas.Children.Clear();
}
}
}
我还尝试在线程中绘制运行“DrawForestFire()”,画布对象位于“this.Dispatcher.Invoke(() => { ... });”中 但这对我没有任何影响。出了什么问题?
而且,对于这种操作,还有比 Canvas 更好的东西吗?
解决方案
与其将 10000 个 Rectangle 元素添加到 Canvas 中,不如将其绘制到单个WriteableBitmap
.
Image
在 XAML 中声明一个元素
<Image x:Name="image"/>
并将 WriteableBitmap 分配给它的 Source 属性。然后使用 DispatcherTimer 更新位图像素:
public partial class MainWindow : Window
{
private const int width = 100;
private const int height = 100;
private readonly Random random = new Random();
private readonly byte[] buffer = new byte[3 * width * height];
private readonly WriteableBitmap bitmap =
new WriteableBitmap(width, height, 96, 96, PixelFormats.Bgr24, null);
public MainWindow()
{
InitializeComponent();
image.Source = bitmap;
var timer = new DispatcherTimer { Interval = TimeSpan.FromMilliseconds(50) };
timer.Tick += OnTimerTick;
timer.Start();
}
private void UpdateBuffer()
{
for (var y = 0; y < height; y++)
{
for (var x = 0; x < width; x++)
{
var i = 3 * (width * y + x);
buffer[i++] = (byte)random.Next(200);
buffer[i++] = (byte)random.Next(200);
buffer[i++] = (byte)random.Next(200);
}
}
}
private async void OnTimerTick(object sender, EventArgs e)
{
await Task.Run(() => UpdateBuffer());
bitmap.WritePixels(new Int32Rect(0, 0, width, height), buffer, 3 * width, 0);
}
}
推荐阅读
- php - 下拉值在第一个空格后被截断
- dart - Fluter - Navigator 不返回(黑屏)
- node.js - 如何将节点 gd 图像转换为我可以通过管道传输的流?
- python - 基于自定义字母顺序python对数组进行排序
- typing - 为什么声音渐进打字慢?
- kotlin - Anko 自定义小部件:editText 不显示错误文本
- php - 带有时区的 DateTime::createFromFormat 确实会改变输出
- windows - 如何使用嵌套的 for 循环。为所有目录做所有文件做的事情
- daml - 如何在现有合同中搜索?例如,使用 accountid 在现有 Accounts 中查找 Account 合约
- python - 如何设置输入以通过请求发送到电报频道的按摩