How to add rulers to a diagram?

I would like to ask a question, how to add a ruler to the Diagram?Like this。。。

Here is the XAML for a sample showing 4 rulers, one on each side of the Diagram:

<!-- Copyright © Northwoods Software Corporation, 2008-2018. All Rights Reserved. -->

<UserControl x:Class="Rulers.Rulers"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:go="http://schemas.nwoods.com/GoXam">
  <UserControl.Resources>
    <DataTemplate x:Key="NodeTemplate">
      <go:NodePanel Sizing="Auto" go:Part.SelectionAdorned="True">
        <Rectangle Fill="Yellow" Stroke="Black" RadiusX="5" RadiusY="5"
                   go:NodePanel.Spot1="0.2 0.2" go:NodePanel.Spot2="0.8 0.8"
                   go:Node.PortId="" go:Node.LinkableFrom="True" go:Node.LinkableTo="True" />
        <TextBlock Text="{Binding Path=Data}" />
      </go:NodePanel>
    </DataTemplate>
  </UserControl.Resources>
  <Grid>
    <Grid.ColumnDefinitions>
      <ColumnDefinition Width="Auto" />
      <ColumnDefinition Width="*" />
      <ColumnDefinition Width="Auto" />
    </Grid.ColumnDefinitions>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto" />
      <RowDefinition Height="*" />
      <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <go:Diagram x:Name="myDiagram" Grid.Column="1" Grid.Row="1"
                GridVisible="True" AllowCopy="False"
                NodeTemplate="{StaticResource NodeTemplate}">
      <go:Diagram.Layout>
        <go:ForceDirectedLayout />
      </go:Diagram.Layout>
    </go:Diagram>

    <Rectangle Grid.Column="0" Grid.Row="0" Fill="White" />
    <Rectangle Grid.Column="2" Grid.Row="0" Fill="White" />
    <Rectangle Grid.Column="2" Grid.Row="2" Fill="White" />
    <Rectangle Grid.Column="0" Grid.Row="2" Fill="White" />
    
    <!-- these intervals match those of the default Diagram.GridPattern -->
    <go:GridPattern x:Name="myLeftRuler" Grid.Column="0" Grid.Row="1"
                    Width="20" CellSize="20 10" Background="White">
      <Path go:GridPattern.Interval="1" StrokeDashArray="0 15 5"  Stroke="LightBlue"
              StrokeThickness="1" go:GridPattern.Figure="HorizontalLine" />
      <Path go:GridPattern.Interval="5" StrokeDashArray="0 12 8"  Stroke="LightBlue" 
              StrokeThickness="1" go:GridPattern.Figure="HorizontalLine" />
      <Path go:GridPattern.Interval="10" StrokeDashArray="0 10 10" Stroke="LightBlue"
              StrokeThickness="1" go:GridPattern.Figure="HorizontalLine" />
      <Path go:GridPattern.Interval="50" StrokeDashArray="0 5 15"  Stroke="Blue"
              StrokeThickness="1" go:GridPattern.Figure="HorizontalLine" />
    </go:GridPattern>

    <go:GridPattern x:Name="myTopRuler" Grid.Column="1" Grid.Row="0"
                    Height="20" CellSize="10 20" Background="White">
      <Path go:GridPattern.Interval="1" StrokeDashArray="0 15 5"  Stroke="Pink"
              StrokeThickness="1" go:GridPattern.Figure="VerticalLine" />
      <Path go:GridPattern.Interval="5" StrokeDashArray="0 12 8"  Stroke="Pink" 
              StrokeThickness="1" go:GridPattern.Figure="VerticalLine" />
      <Path go:GridPattern.Interval="10" StrokeDashArray="0 10 10" Stroke="Pink"
              StrokeThickness="1" go:GridPattern.Figure="VerticalLine" />
      <Path go:GridPattern.Interval="50" StrokeDashArray="0 5 15"  Stroke="Red"
              StrokeThickness="1" go:GridPattern.Figure="VerticalLine" />
    </go:GridPattern>

    <go:GridPattern x:Name="myRightRuler" Grid.Column="2" Grid.Row="1"
                    Width="20" CellSize="20 10" Background="White">
      <Path go:GridPattern.Interval="1" StrokeDashArray="5 15"  Stroke="Goldenrod"
              StrokeThickness="1" go:GridPattern.Figure="HorizontalLine" />
      <Path go:GridPattern.Interval="5" StrokeDashArray="8 12"  Stroke="Goldenrod" 
              StrokeThickness="1" go:GridPattern.Figure="HorizontalLine" />
      <Path go:GridPattern.Interval="10" StrokeDashArray="10 10" Stroke="Goldenrod"
              StrokeThickness="1" go:GridPattern.Figure="HorizontalLine" />
      <Path go:GridPattern.Interval="50" StrokeDashArray="15 5"  Stroke="Orange"
              StrokeThickness="1" go:GridPattern.Figure="HorizontalLine" />
    </go:GridPattern>

    <go:GridPattern x:Name="myBottomRuler" Grid.Column="1" Grid.Row="2"
                    Height="20" CellSize="10 20" Background="White">
      <Path go:GridPattern.Interval="1" StrokeDashArray="5 15"  Stroke="LightGreen"
              StrokeThickness="1" go:GridPattern.Figure="VerticalLine" />
      <Path go:GridPattern.Interval="5" StrokeDashArray="8 12"  Stroke="LightGreen" 
              StrokeThickness="1" go:GridPattern.Figure="VerticalLine" />
      <Path go:GridPattern.Interval="10" StrokeDashArray="10 10" Stroke="LightGreen"
              StrokeThickness="1" go:GridPattern.Figure="VerticalLine" />
      <Path go:GridPattern.Interval="50" StrokeDashArray="15 5"  Stroke="Green"
              StrokeThickness="1" go:GridPattern.Figure="VerticalLine" />
    </go:GridPattern>
  </Grid>
</UserControl>

And here is the corresponding C# code:

/* Copyright © Northwoods Software Corporation, 2008-2018. All Rights Reserved. */

using System;
using System.Collections.ObjectModel;
using System.Windows;
using System.Windows.Controls;
using Northwoods.GoXam;
using Northwoods.GoXam.Model;
using Northwoods.GoXam.Tool;

namespace Rulers {
  /// <summary>
  /// Interaction logic for Rulers.xaml
  /// </summary>
  public partial class Rulers : UserControl {
    public Rulers() {
      InitializeComponent();

      var model = new GraphLinksModel<String, String, String, UniversalLinkData>();
      model.NodesSource = new ObservableCollection<String>() {
            "Lambda", "Mu", "Nu", "Xi",
            "Alpha", "Beta", "Gamma", "Delta", "Epsilon",
            "Zeta", "Eta", "Theta", "Iota", "Kappa",
            "Omicron", "Pi", "Rho", "Sigma", "Tau",
            "Upsilon", "Phi", "Chi", "Psi", "Omega"
      };
      model.Modifiable = true;
      model.HasUndoManager = true;
      myDiagram.Model = model;

      myDiagram.TemplateApplied += (sndr, evt) => {
        myDiagram.Panel.ViewportBoundsChanged += (s, e) => { UpdateRulersForDiagram(); };
      };
    }

    private void UpdateRulersForDiagram() {
      // the 10 and 20 match the values used in the GridPatterns
      // 10 is the distance between tick marks
      // 20 is the GridPattern thickness and the StrokeDashArray length
      double scale = myDiagram.Panel.Scale;
      Size vert = new Size(20, 10*scale);
      myLeftRuler.CellSize = vert;
      myRightRuler.CellSize = vert;
      Size horiz = new Size(10*scale, 20);
      myTopRuler.CellSize = horiz;
      myBottomRuler.CellSize = horiz;

      Point pos = myDiagram.Panel.Position;
      pos.X = -pos.X*scale;
      pos.Y = -pos.Y*scale;
      myLeftRuler.Origin = pos;
      myTopRuler.Origin = pos;
      myRightRuler.Origin = pos;
      myBottomRuler.Origin = pos;
    }
  }
}

Thank you,Walter.
According to your previous answer I have been able to add rulers to both sides of the Diagram, but I still have a question: how to scale the ruler (to locate the coordinates of the current mouse on the Diagram)?

I’m not sure what you want to do. The rulers ought to automatically be adjusting as the user scrolls the diagram or zooms (changes the scale of) the diagram. That’s what the UpdateRulersForDiagram method is doing.

The current mouse point in model coordinates is given by Diagram.LastMousePointInModel.

Emmm, I want to show the scale value on the ruler.

Oh, that kind of “scale”. OK, add a WPF Shape, perhaps a Line, as a sibling to the GridPattern, and position it where you want.

After the last exchange, I tried many methods and still failed to add the scale value to the scale.
Please also help me write a sample. Thank you

Are you getting the “ruler” drawn OK? Is it automatically “scrolling” the tick marks as the diagram is scrolled or panned? Is it automatically changing the distance between tick marks as the diagram is zoomed?

Or have you not gotten to that point? I really can’t tell what you have done, what is working satisfactorily, and what still needs to be done.

My “ruler” is ok,it is automatically “scrolling” the tick marks as the diagram is scrolled or panned,it is automatically changing the distance between tick marks as the diagram is zoomed.But my ruler doesn’t have a scale.


I want to achieve this effect

Sorry, but I don’t have any code for that. You’ll have to make sure there are enough TextBlocks showing the desired strings and positioned at the expected locations. I don’t know if it would be better to use an ItemsControl or not.