ub3*_*t4r 3 c# wpf optimization canvas
我Canvas在WPF中使用了一个绘制许多彩色矩形的方法,但是添加它们时,程序运行速度非常慢。我尝试了不同的选择,例如将它们添加到中,Array然后一次全部添加,并使用a Image而不是Canvas来支付它们,但是它们似乎并没有做什么。我有将代码引导到线程中的图形,但是由于C#规则,我必须在主线程中包含图形部分。我还应该注意,问题出在我的计算机上(它运行的是带有14GB DDR2 RAM的Intel Core i7)。
这是添加矩形的代码。它已运行超过83,000次。
private void AddBlock(double left, double top, double width, double height, Brush color)
{
if (this.Dispatcher.Thread != Thread.CurrentThread)
{
this.Dispatcher.Invoke(new Action<double, double, double, double, Brush>(this.AddBlock), left, top, width, height, color);
return;
}
Rectangle rect = new Rectangle() { Width = width, Height = height, Fill = color, SnapsToDevicePixels = true };
this.canvas.Children.Add(rect);
Canvas.SetLeft(rect, left);
Canvas.SetTop(rect, top);
}
Run Code Online (Sandbox Code Playgroud)
注意:正如我在下面的评论中所述,我希望有一些东西可以让它在单独的线程上运行(即使涉及使用P / Invoke),因为似乎没有可行的解决方案,仅使用C#和WPF 。
有什么建议么?
使用OnRender方法
我创建了一个继承Canvas的类,并重写OnRender方法以获取DrawingContext并使用它进行绘制。所以在代码中,我没有将rects添加到画布上,而是添加到了新类的rect列表中,并InvalidateVisual();在添加完后使用Dispatcher进行了调用。
class MyCanvas:Canvas
{
public class MyRect
{
public Rect Rect;
public Brush Brush;
}
public List<MyRect> rects = new List<MyRect>();
protected override void OnRender(System.Windows.Media.DrawingContext dc)
{
base.OnRender(dc);
for (int i = 0; i < rects.Count; i++)
{
MyRect mRect = rects[i];
dc.DrawRectangle(mRect.Brush, null, mRect.Rect);
}
}
}
Run Code Online (Sandbox Code Playgroud)
a
<l:MyCanvas x:Name="canvas"/>
Run Code Online (Sandbox Code Playgroud)
添加矩形
private void AddBlock(double left, double top, double width, double height, Brush color)
{
canvas.rects.Add(new MyCanvas.MyRect() { Brush = color, Rect = new Rect(left, top, width, height) });
}
Run Code Online (Sandbox Code Playgroud)
准备好后刷新,应在调度程序上进行
canvas.InvalidateVisual();
Run Code Online (Sandbox Code Playgroud)
这似乎是使用WPF最快的方法,您可能不需要走GDI +或pinvoke。在我的系统中进行测试的过程中,原始代码大约花费500 ms了渲染时间830 rects,几何体花费了大约400 ms来进行渲染,而这种方法83,000 rects在不到100 ms
我也建议您添加一些缓存,以避免过度渲染
使用几何的解决方案
类级变量
GeometryGroup gGroup;
Run Code Online (Sandbox Code Playgroud)
使用以下代码进行准备
DrawingBrush dBrush= new DrawingBrush();
gGroup = new GeometryGroup();
GeometryDrawing gDrawing = new GeometryDrawing(Brushes.Red, null, gGroup);
dBrush.Drawing = gDrawing;
Canvas.Background = dBrush
Run Code Online (Sandbox Code Playgroud)
然后是你的代码
private void AddBlock(double left, double top, double width, double height, Brush color)
{
if (this.Dispatcher.Thread != Thread.CurrentThread)
{
this.Dispatcher.Invoke(new Action<double, double, double, double, Brush>(this.AddBlock), left, top, width, height, color);
return;
}
//color need to figure out as it is added in GeometryDrawing
//currently Brushes.Red defined earlier
gGroup.Children.Add(new RectangleGeometry(new Rect(left, top, width, height)));
}
Run Code Online (Sandbox Code Playgroud)
该示例可以帮助您达到相同的目的。我还将尽快进行一些实验,以更快的方式获得所需的结果。
| 归档时间: |
|
| 查看次数: |
4116 次 |
| 最近记录: |