Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

Grid/Canvas Lined and Squared

0.00/5 (No votes)
25 Nov 2013 1  
How to produce a dynamic lined or squared background on a canvas/grid

Introduction

Imagine a grid/canvas you want to present lined or squared to the user:

Using MVVM and WPF, you can avoid overloading your Grid or Canvas with many Line-objects on the screen and you can avoid a lot of work whenever redrawing and adapting the lines to user inputs is necessary.

Background

Sometimes it is really useful - or necessary - to draw many lines by yourself. But that can become rather challenging. Using StreamGeometry and a small algorithm, you can do the whole thing with one Path-object for all horizontal lines (and a second Path-object for all vertical lines if needed) on the screen and updating them via RaisePropertyChanged whenever necessary. Fast as hell. That's it!

This code-example first used Solution A. Today I had the idea of Solution B, which should make it even easier.

Using the Code

In your WPF/XAML, simply add:

<Path Data="{Binding MyHorizontalLines}" Stroke="{Binding MyColor}" StrokeThickness="1" 
  RenderOptions.EdgeMode="Aliased" 
  IsHitTestVisible="False" HorizontalAlignment="Left" 
  VerticalAlignment="Top" />

<Path Data="{Binding MyVerticalLines}" Stroke="{Binding MyColor}" 
  StrokeThickness="1" 
  RenderOptions.EdgeMode="Aliased" IsHitTestVisible="False" 
  HorizontalAlignment="Left" VerticalAlignment="Top" />

In your viewmodel, of course, you have the properties MyHorizontalLines and MyVerticalLines as StreamGeometry and MyColor as SolidColorBrush (the desired color of your lines).

And then, you only call the following small method in order to produce all lines on the screen as only one StreamGeometry (one for all horizontal lines and, if needed, one for all vertical lines):

Solution A: 

public static StreamGeometry MyLines (Point StartPoint, bool Horizontal, 
         int LengthOfLines, int NumberOfLines, int LineDistance)
{
    StreamGeometry lines = new StreamGeometry();
    Point toPoint;
    using (StreamGeometryContext strG = lines.Open())
    {
        toPoint = Horizontal ? new Point(StartPoint.X, 
        	StartPoint.Y) : new Point(StartPoint.Y, StartPoint.X);
        strG.BeginFigure(toPoint, false, false);
        for (var i = 0; i < NumberOfLines * 2 - 1; i++)
        {
            if (i % 2 == 1)
                StartPoint = new Point(StartPoint.X, StartPoint.Y + LineDistance);
            else
                StartPoint = new Point(StartPoint.X + 
                	(i % 4 == 0 ? LengthOfLines : -LengthOfLines), StartPoint.Y);
            toPoint = Horizontal ? new Point(StartPoint.X, StartPoint.Y) : 
            	new Point(StartPoint.Y, StartPoint.X);
            strG.LineTo(toPoint, i % 2 == 0, false);
        }
    }
    lines.Freeze();
    return lines;
}

Solution B:

public static StreamGeometry MyLines(Point StartPoint, int LengthOfLines, int NumberOfLines, int LineDistance)
{
    StreamGeometry lines = new StreamGeometry();
    using (StreamGeometryContext ctxt = lines.Open())
    {
        ctxt.BeginFigure(new Point(0, 0), false, false);
        for (var i = 0; i < NumberOfLines; i++)
        {
            ctxt.LineTo(StartPoint, false, false);
            StartPoint = new Point(StartPoint.X + LengthOfLines, StartPoint.Y); 
            ctxt.LineTo(StartPoint, true, false);
            StartPoint = new Point(StartPoint.X - LengthOfLines, StartPoint.Y + LineDistance);
        }
    }
    lines.Freeze();
    return lines;
}  

(Change X and Y for vertical lines.) 

Afterwards, in your ViewModel with the mentioned properties (including the RaisePropertyChanged() in the setter as usual), you can always fill these properties with the updated StreamGeometry of the lines:

MyHorizontalLines = MyLines (new Point(0, 0), true, 600, 10, 15);
MyVerticalLines = MyLines(new Point(0, 0), false, 1000, 50, 50);    

Points of Interest

The magic effect comes from the LineTo-method of the StreamGeometryContext: in its second parameter you can tell this method whether to draw a line or simply move to the next point ("line" in our case) without drawing.

In addition to that, our one or two (frozen) line-constructions as Data of the one or two Path-objects in the WPF/XAML are managed by MVVM really quickly.

History

  • 23.11.2013: Originally posted
  • 25.11.2013: Chart and Solution B added 

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here