我正在做简单的图形控制wpf
。我无法解释也无法解决性能问题:与 winform 相比,它太慢了。也许我做错了什么。
我准备了demo来演示这个问题。
这是测试控制:
public class Graph : FrameworkElement
{
private Point _mouse;
private Point _offset = new Point(500, 500);
public Graph()
{
Loaded += Graph_Loaded;
}
private void Graph_Loaded(object sender, RoutedEventArgs e)
{
// use parent container with background to receive mouse events too
var parent = VisualTreeHelper.GetParent(this) as FrameworkElement;
if (parent != null)
parent.MouseMove += (s, a) => OnMouseMove(a);
}
protected override void OnRender(DrawingContext context)
{
// designer bugfix
if (DesignerProperties.GetIsInDesignMode(this))
return;
Stopwatch watch = new Stopwatch();
watch.Start();
// generate some big figure (try to vary that 2000!)
var radius = 1.0;
var figures = new List<LineSegment>();
for (int i = 0; i < 2000; i++, radius += 0.1)
{
var segment = new LineSegment(new Point(radius * Math.Sin(i) + _offset.X, radius * Math.Cos(i) + _offset.Y), true);
segment.Freeze();
figures.Add(segment);
}
var geometry = new PathGeometry(new[] { new PathFigure(figures[0].Point, figures, false) });
geometry.Freeze();
var pen = new Pen(Brushes.Black, 5);
pen.Freeze();
context.DrawGeometry(null, pen, geometry);
// measure time
var time = watch.ElapsedMilliseconds;
Dispatcher.InvokeAsync(() =>
{
Window.GetWindow(this).Title = string.Format("{0:000}ms; {1:000}ms", time, watch.ElapsedMilliseconds);
}, DispatcherPriority.Loaded);
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
var mouse = e.GetPosition(this);
if (e.LeftButton == MouseButtonState.Pressed)
{
// change graph location
_offset.X += mouse.X - _mouse.X;
_offset.Y += mouse.Y - _mouse.Y;
InvalidateVisual();
}
// remember last mouse position
_mouse = mouse;
}
}
下面是在 xaml 中使用它的方法:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:WpfApplication1"
Title="MainWindow" Height="350" Width="525" WindowState="Maximized">
<Grid Background="White">
<local:Graph/>
</Grid>
</Window>
备注:控件会绘制图形,可以用鼠标移动图形:
它将在标题中显示 2 个测量值:第一个是花费了多长时间OnRender()
完成,第二个是实际渲染花费的时间(渲染后第一次调用)。
尝试改变这一点2000
: 环境1000
makes moving舒服的,3000
就像在重新绘制图形之前有半秒的延迟(在我的电脑上)。
问题:
- 好用吗
InvalidateVisual()
更新图形偏移量MouseMove
?如果不好,什么是正确的无效技术?
- 冻结,有很多,没有任何明显的效果。我是否需要使用它们?
- 看起来只需要
5ms
完成渲染,但主观移动需要更长的时间(200ms+)。这是为什么?
主要问题当然是性能,为什么这么糟糕?我可以在 winform 控件中绘制几十万行,直到它变得像我的 wpf 控件只用 1000 行一样草率... =(
我找到了最后一个问题的答案。使用鼠标移动时,渲染时间的测量无法正常工作。但是如果调整窗口大小,那么第二次就会变成300ms
(在我的电脑上2000
人物)。所以这不是一个鼠标错误无效(第一个问题),但是渲染确实很慢。