我還沒有發現任何有用的無論是谷歌或堆棧溢出或根本沒有答案(或者我只是不知道要搜索什麼) - 我可以得到的最接近的問題是這一個:The reason behind slow performance in WPFWPF MouseMove InvalidateVisual OnRender更新非常慢
但我想在這個簡單的程序中得到這個滯後的底部,也許我只是沒有做正確的事情。
我在UI元素的OnRender()中使用它們之間的連線渲染了大約2000個點,本質上創建了一個折線圖。沒關係,但我想用MouseMove平移圖形。這工作正常,但它是問題的LAG。每當用鼠標拖動時我都會期待一個平滑的更新,我認爲用它們之間的連線重新繪製2000點將會是在公園裏散步的一個i5 CPU。但即使在家中筆記本電腦的低分辨率下,速度也非常慢。所以我查了一下Performance Profiler。 OnRender()函數幾乎不使用任何CPU。
事實證明,這是情況正在發生變化,並使用如此多的CPU佈局。
「佈局」走的是最長時間來完成
現在,我聽說過這個詞視覺樹踢一下,但是在幾乎沒有任何的視覺效果這個簡單的項目。只是一個主窗口上的UI元素。它使用的是繪圖上下文,我認爲繪圖上下文會像位圖一樣繪製,還是繪製具有自己的事件/點擊框等的UI元素?因爲我想要的只是UIElement,就像一個圖像,但也處理鼠標事件,所以我可以拖動整個事物(或用鼠標滾輪縮放)。
所以問題:
- 如果佈局導致了緩慢/滯後,我該如何避免這種情況?
- 我也注意到很多垃圾收集都有意義,但我不希望它在渲染過程中發生。我寧願這樣做,而它閒置。但是如何?
這裏是源:
.cs文件
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Media;
namespace SlowChart
{
public class SlowChartClass : UIElement
{
List<Point> points = new List<Point>();
double XAxis_Width = 2000;
double XAxis_LeftMost = 0;
double YAxis_Height = 300;
double YAxis_Lowest = -150;
Point mousePoint;
double XAxis_LeftMostPan = 0;
double YAxis_LowestPan = 0;
public SlowChartClass()
{
for (int i = 0; i < 2000; i++)
{
double cos = (float)Math.Cos(((double)i/100) * Math.PI * 2);
cos *= 100;
points.Add(new Point(i, cos));
}
MouseDown += SlowChartClass_MouseDown;
MouseUp += SlowChartClass_MouseUp;
MouseMove += SlowChartClass_MouseMove;
}
private void SlowChartClass_MouseMove(object sender, System.Windows.Input.MouseEventArgs e)
{
if (IsMouseCaptured)
{
XAxis_LeftMost = XAxis_LeftMostPan - (e.GetPosition(this).X - mousePoint.X);
YAxis_Lowest = YAxis_LowestPan + (e.GetPosition(this).Y - mousePoint.Y);
InvalidateVisual();
}
}
private void SlowChartClass_MouseUp(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
ReleaseMouseCapture();
}
private void SlowChartClass_MouseDown(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
mousePoint = e.GetPosition(this);
XAxis_LeftMostPan = XAxis_LeftMost;
YAxis_LowestPan = YAxis_Lowest;
CaptureMouse();
}
double translateYToScreen(double Y)
{
double y = RenderSize.Height - (RenderSize.Height * ((Y - YAxis_Lowest)/YAxis_Height));
return y;
}
double translateXToScreen(double X)
{
double x = (RenderSize.Width * ((X - XAxis_LeftMost)/XAxis_Width));
return x;
}
protected override void OnRender(DrawingContext drawingContext)
{
bool lastPointValid = false;
Point lastPoint = new Point();
Rect window = new Rect(RenderSize);
Pen pen = new Pen(Brushes.Black, 1);
// fill background
drawingContext.DrawRectangle(Brushes.White, null, window);
foreach (Point p in points)
{
Point screenPoint = new Point(translateXToScreen(p.X), translateYToScreen(p.Y));
if (lastPointValid)
{
// draw from last to this one
drawingContext.DrawLine(pen, lastPoint, screenPoint);
}
lastPoint = screenPoint;
lastPointValid = true;
}
// draw axis
drawingContext.DrawText(new FormattedText(XAxis_LeftMost.ToString("0.0") + "," + YAxis_Lowest.ToString("0.0"),CultureInfo.InvariantCulture,FlowDirection.LeftToRight,new Typeface("Arial"),12,Brushes.Black),new Point(0,RenderSize.Height-12));
}
}
}
.XAML文件
<Window x:Class="SlowChart.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SlowChart"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<local:SlowChartClass/>
</Grid>
</Window>
更好地使用TranslateTransform而不是在平移時重新渲染所有內容。您也可以繪製折線而不是2000行。 – Clemens
我在這個問題/答案中找到了更相關的解決方案https://stackoverflow.com/questions/25450979/terrible-performance-of-custom-drawn-control(使用Translate Transform)。乾杯 – pm101