问题
Recently I switched to DrawingVisuals
to increase the performance of our trending graphs (especially zooming and panning).
Here's the code I have:
blocksToBeRendered = (baseItem as AvgCurve).GetStreamGeometryBlocks(ActualWidth, ActualHeight, _minPoint.X, _maxPoint.X, FixTimeStep ? _timeStep : 0, IsMainChart);
Pen stroke = new Pen((baseItem as AvgCurve).LineBrush, 1);
foreach (GeometryGroup group in blocksToBeRendered)
{
if (group.Children.Count != 0)
{
if (!cachedBlocks[baseItem].Any(x => x.Children[0] == group.Children[0]))
{
cachedBlocks[baseItem].Add(group);
ImprovedDrawingVisual vis = new ImprovedDrawingVisual();
BitmapCache cache = new BitmapCache() { SnapsToDevicePixels = true };
vis.CacheMode = cache;
using (DrawingContext context = vis.RenderOpen())
{
RenderOptions.SetEdgeMode(group, EdgeMode.Aliased);
if (group.Children.Count > 0)
{
context.DrawGeometry(null, stroke, group.Children[0]);
}
}
_host.VisualCollection.Add(vis);
}
}
}
This is the ImprovedDrawingVisual
:
public class ImprovedDrawingVisual: DrawingVisual
{
public ImprovedDrawingVisual()
{
VisualEdgeMode = EdgeMode.Aliased;
VisualBitmapScalingMode = BitmapScalingMode.NearestNeighbor;
}
}
Now, the geometries do have Transforms
, which might be important.
What happens is that the graphs are drawn nicely without bitmap caching (1 px lines), but when I turn on bitmap caching, parts of the graph go all blurry sometimes.
Does anyone know how I can fix this? I tried changing the RenderAtScale
of the DrawingVisual
or turning off the EdgeMode
setting, but that doesn't help.
EDIT: Left out the brush fill geometry to avoid confusion since it's not relevant here.
回答1:
If you decide to try GDI+
in wpf
, then drawing will looks like this:
using GDI = System.Drawing;
private int _counter; // count redraws
protected override void OnRender(DrawingContext context)
{
if (Figures != null && RenderSize.Height > 0 && RenderSize.Width > 0)
using (var bitmap = new GDI.Bitmap((int)RenderSize.Width, (int)RenderSize.Height))
{
using (var graphics = GDI.Graphics.FromImage(bitmap))
foreach (var figure in Figures)
figure.Render(this, graphics);
// draw image
var hbitmap = bitmap.GetHbitmap();
var size = bitmap.Width * bitmap.Height * 4;
GC.AddMemoryPressure(size);
var image = Imaging.CreateBitmapSourceFromHBitmap(hbitmap, IntPtr.Zero, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
image.Freeze();
context.DrawImage(image, new Rect(RenderSize));
DeleteObject(hbitmap);
GC.RemoveMemoryPressure(size);
// trigger garbage collecting
if (_counter++ > 10)
GC.Collect(3);
}
}
This basically renders Graph
in place (no deffered wpf
rendering, well, only blitting of final image
). You call InvalidateVisual()
to redraw graph. Notice GC
thingies, they are must (especially periodic garbage collection if graph gets redrawn frequently).
In my code Figures
is a list of non-visuals (simple classes, implementing GDI rendering as well). And you have visual children. It's the problem, which I leave for you to solve. The benefit is very high performance.
来源:https://stackoverflow.com/questions/26138099/bitmap-cache-on-drawingvisual-has-blurry-parts