8

I'm drawing a graph in a WPF application, but lines drawn using drawingContext.DrawLine(...) are drawn to sub-pixel boundaries.

I'm able to get them to look nice by creating Line objects, but I don't want to create tens of thousands of those every time the visual is invalidated.

How can I force them to fit to pixels?

Carson Myers
  • 37,678
  • 39
  • 126
  • 176
  • good question, a question on my part, and I hope I understand you correctly, so you chose to draw a graph, doing everything (every line) yourself - super impressive, my head's down. Now do you need to? is it possible for you to use a library to do the heavy lifting for you? ..unless of course, you are writing your own charting component. – denis morozov Apr 21 '12 at 04:21
  • @denismorozov it's my own charting component. I'm graphing page references from a simulated memory manager for a school project. We're investigating how the memory operations of different algorithms go through phases, and trying different page replacement algorithms to minimize page faults. It's really fun :) – Carson Myers Apr 21 '12 at 04:25
  • very cool! I am thinking about play with my own charting control too. Good luck! – denis morozov Apr 21 '12 at 13:32

2 Answers2

12

You may draw the lines into a derived DrawingVisual that has the protected VisualEdgeMode property set to EdgeMode.Aliased:

public class MyDrawingVisual : DrawingVisual
{
    public MyDrawingVisual()
    {
        VisualEdgeMode = EdgeMode.Aliased;
    }
}

public class DrawingComponent : FrameworkElement
{
    private DrawingVisual visual = new MyDrawingVisual();

    public DrawingComponent()
    {
        AddVisualChild(visual);

        using (DrawingContext dc = visual.RenderOpen())
        {
            dc.DrawLine(new Pen(Brushes.Black, 1d), new Point(100, 100), new Point(100, 200));
            dc.DrawLine(new Pen(Brushes.Black, 1d), new Point(105.5, 100), new Point(105.5, 200));
            dc.DrawLine(new Pen(Brushes.Black, 1d), new Point(112, 100), new Point(112, 200));
        }
    }

    protected override int VisualChildrenCount
    {
        get { return 1; }
    }

    protected override Visual GetVisualChild(int index)
    {
        return visual;
    }
}

Strange enough, but calling RenderOptions.SetEdgeMode(visual, EdgeMode.Aliased) on a non-derived DrawingVisual doesn't do the job.

Clemens
  • 123,504
  • 12
  • 155
  • 268
2

That's great.

Another option (more complicated in that case) is using RenderOptions.SetEdgeMode on a DrawingGroup:

https://stackoverflow.com/a/16984921/2463642

Community
  • 1
  • 1
MaMazav
  • 1,773
  • 3
  • 19
  • 33