A graph rendered with Graphviz4Net can contain nodes connected with edges. Each edge can have an arrow at each of it's ends, a label in the middle of the edge, and a label at each of the edge's ends. Nodes can be grouped into sub-graphs. Such sub-graph has a border and a label. Sub-graphs can be connected with edges, two nodes inside two different sub-graphs can be connected with an edge, a node and a sub-graph can be connected with an edge.

Every element that is in bold in the previous paragraph can be fully customized using WPF data templates mechanism.

How it works in general

All elements of a graph are placed inside a Canvas and then their attached dependency properties Top and Left are updated by Graphviz4Net so they form a "nice" graph layout. The trick is that Graphviz4Net does not add some specific WPF controls to the Canvas, but it uses ContentPresenter control. The ContentPresenter has a property Content and the type of it's value is used by WPF to choose the DataTemplate for it. For each of the graph elements, Graphviz4Net sets the Content property to a corresponding view model object. This view model object contains necessary data, e.g. the view model for a label contains the Text property.

This all means that any of the graph elements can be fully customized by defining the DataTemplate for the type of the view model of this element (one has to set the UseContentPresenterForAllElements dependency property of the GraphLayout WPF control to true).

Some elements, e.g. edge labels, have fixed view models (LabelViewModel). Other elements may have a view model defined by a user - those are nodes and edge arrows, so, thanks to this, two nodes can have different view models and thus different DataTemplates.

Example

this.Graph = new Graph();
var a = new Person { Name = "Jonh", Avatar = "./Avatars/avatar1.jpg" };
var b = new Person { Name = "Michael", Avatar = "./Avatars/avatar2.gif" };
this.Graph.AddVertex(a);
this.Graph.AddVertex(b);
this.Graph.AddEdge(new Edge(a, b, new DiamondArrow()) { Label = "Boss" });
  
<Window.Resources>
 <DataTemplate DataType="{x:Type Example:Person}">
   <Border BorderBrush="Black" BorderThickness="1" Padding="0" CornerRadius="5">
     <StackPanel Orientation="Horizontal">
       <Image Source="{Binding Avatar}" Width="32" Height="32" Margin="5" VerticalAlignment="Top"/>
       <StackPanel Orientation="Vertical" Margin="2">
         <TextBlock Text="{Binding Name}"/>
         <!-- ... -->
 </DataTemplate>
 
 <DataTemplate DataType="{x:Type Example:DiamondArrow}">
   <Canvas Width="6" Height="11">
     <Polygon Points="3,0 6,5 3,10 0,5" Stroke="Black" StrokeThickness="1" Fill="Black"/>
   </Canvas>
 </DataTemplate>

 <DataTemplate DataType="{x:Type ViewModels:EdgeViewModel}">
   <Path Data="{Binding Data}" Stroke="Black" StrokeThickness="1"/>
 </DataTemplate>
</Window.Resources>

<WPF:GraphLayout Graph="{Binding Graph}"/>

Last edited Feb 3, 2012 at 1:56 PM by stevesindelar, version 5

Comments

No comments yet.