GraphSharp Tutorials

来源:互联网 发布:网络培训学校 编辑:程序博客网 时间:2024/05/23 19:21

本文转自http://sachabarber.net/?p=815   created by Sacha Barber

PRETTY COOL GRAPHS IN WPF

I have just finished writing up a new article for www.codeproject.com for which I will write another blog post about. Thing is, when I was looking into parts of that article I wanted to use some graphs in WPF, and had to have a hunt around to see what was out there.

After a look about I found a truly excellent graphing library for WPF which is completely free. It’s a www.codeplex.com project called “GraphSharp” which is freely available atgraphsharp.codeplex.com.

I also figured it may be good to show people how to get up and running with GraphSharp in this standalone blog as the new article I published does absolutely no hand holding about the graph creation, as that was not really what the new article is about.

So how do we use GraphSharp then, well we need to do a couple of things

1. Create a customised Vertex type

The 1st step is to define a custom Vertex for the graph such that you can store additional information for each Vertex. This is done as follows:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Diagnostics;namespace GraphSharpDemo{    /// <summary>    /// A simple identifiable vertex.    /// </summary>    [DebuggerDisplay("{ID}-{IsMale}")]    public class PocVertex    {        public string ID { get; private set; }        public bool IsMale { get; private set; }        public PocVertex(string id, bool isMale)        {            ID = id;            IsMale = isMale;        }        public override string ToString()        {            return string.Format("{0}-{1}", ID, IsMale);        }    }}

2. Create a customised Edge type

The next step is to define a custom Edge type, you may want to show some extra information when the Edge is hovered over for example. This is done as follows:

using QuickGraph;using System.Diagnostics;namespace GraphSharpDemo{    /// <summary>    /// A simple identifiable edge.    /// </summary>    [DebuggerDisplay("{Source.ID} -> {Target.ID}")]    public class PocEdge : Edge<PocVertex>    {        public string ID        {            get;            private set;        }        public PocEdge(string id, PocVertex source, PocVertex target)            : base(source, target)        {            ID = id;        }    }}

3. Create a customised Graph

If you have custom Vertex/Edge you will need to create a custom Graph that knows about these custom types. Again this is very easily achieved, using the following code:

using System;using System.Collections.Generic;using System.Linq;using System.Text;using QuickGraph;namespace GraphSharpDemo{    public class PocGraph : BidirectionalGraph<PocVertex, PocEdge>    {        public PocGraph() { }        public PocGraph(bool allowParallelEdges)            : base(allowParallelEdges) { }        public PocGraph(bool allowParallelEdges, int vertexCapacity)            : base(allowParallelEdges, vertexCapacity) { }    }}

4. Create a customised GraphLayout

Using GraphSharp we also need to create a custom LayoutTyppe for the custom graph, which is done as follows:

public class PocGraphLayout : GraphLayout<PocVertex, PocEdge, PocGraph> { }

5. Create a ViewModel

Since we are using WPF, why not follow best practices and use MVVM for it, which obviously means creating a ViewModel. Here is an example ViewModel that can be set as the DataContext for a Window/UserControl that hosts the GraphSharp graphing controls.

using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.ComponentModel;using GraphSharp.Controls;namespace GraphSharpDemo{    public class MainWindowViewModel : INotifyPropertyChanged    {        #region Data        private string layoutAlgorithmType;        private PocGraph graph;        private List<String> layoutAlgorithmTypes = new List<string>();        #endregion        #region Ctor        public MainWindowViewModel()        {            Graph = new PocGraph(true);            List<PocVertex> existingVertices = new List<PocVertex>();            existingVertices.Add(new PocVertex("Sacha Barber", true)); //0            existingVertices.Add(new PocVertex("Sarah Barber", false)); //1            existingVertices.Add(new PocVertex("Marlon Grech", true)); //2            existingVertices.Add(new PocVertex("Daniel Vaughan", true)); //3            existingVertices.Add(new PocVertex("Bea Costa", false)); //4            foreach (PocVertex vertex in existingVertices)                Graph.AddVertex(vertex);            //add some edges to the graph            AddNewGraphEdge(existingVertices[0], existingVertices[1]);            AddNewGraphEdge(existingVertices[0], existingVertices[2]);            AddNewGraphEdge(existingVertices[0], existingVertices[3]);            AddNewGraphEdge(existingVertices[0], existingVertices[4]);            AddNewGraphEdge(existingVertices[1], existingVertices[0]);            AddNewGraphEdge(existingVertices[1], existingVertices[2]);            AddNewGraphEdge(existingVertices[1], existingVertices[3]);            AddNewGraphEdge(existingVertices[2], existingVertices[0]);            AddNewGraphEdge(existingVertices[2], existingVertices[1]);            AddNewGraphEdge(existingVertices[2], existingVertices[3]);            AddNewGraphEdge(existingVertices[2], existingVertices[4]);            AddNewGraphEdge(existingVertices[3], existingVertices[0]);            AddNewGraphEdge(existingVertices[3], existingVertices[1]);            AddNewGraphEdge(existingVertices[3], existingVertices[3]);            AddNewGraphEdge(existingVertices[3], existingVertices[4]);            AddNewGraphEdge(existingVertices[4], existingVertices[0]);            AddNewGraphEdge(existingVertices[4], existingVertices[2]);            AddNewGraphEdge(existingVertices[4], existingVertices[3]);            string edgeString = string.Format("{0}-{1} Connected",                 existingVertices[0].ID, existingVertices[0].ID);            Graph.AddEdge(new PocEdge(edgeString, existingVertices[0], existingVertices[1]));            Graph.AddEdge(new PocEdge(edgeString, existingVertices[0], existingVertices[1]));            Graph.AddEdge(new PocEdge(edgeString, existingVertices[0], existingVertices[1]));            Graph.AddEdge(new PocEdge(edgeString, existingVertices[0], existingVertices[1]));            //Add Layout Algorithm Types            layoutAlgorithmTypes.Add("BoundedFR");            layoutAlgorithmTypes.Add("Circular");            layoutAlgorithmTypes.Add("CompoundFDP");            layoutAlgorithmTypes.Add("EfficientSugiyama");            layoutAlgorithmTypes.Add("FR");            layoutAlgorithmTypes.Add("ISOM");            layoutAlgorithmTypes.Add("KK");            layoutAlgorithmTypes.Add("LinLog");            layoutAlgorithmTypes.Add("Tree");            //Pick a default Layout Algorithm Type            LayoutAlgorithmType = "LinLog";        }        #endregion        #region Private Methods        private PocEdge AddNewGraphEdge(PocVertex from, PocVertex to)        {            string edgeString = string.Format("{0}-{1} Connected", from.ID, to.ID);            PocEdge newEdge = new PocEdge(edgeString, from, to);            Graph.AddEdge(newEdge);            return newEdge;        }        #endregion        #region Public Properties        public List<String> LayoutAlgorithmTypes        {            get { return layoutAlgorithmTypes; }        }        public string LayoutAlgorithmType        {            get { return layoutAlgorithmType; }            set            {                layoutAlgorithmType = value;                NotifyPropertyChanged("LayoutAlgorithmType");            }        }        public PocGraph Graph        {            get { return graph; }            set            {                graph = value;                NotifyPropertyChanged("Graph");            }        }        #endregion        #region INotifyPropertyChanged Implementation        public event PropertyChangedEventHandler PropertyChanged;        private void NotifyPropertyChanged(String info)        {            if (PropertyChanged != null)            {                PropertyChanged(this, new PropertyChangedEventArgs(info));            }        }        #endregion    }}

6. Create and host the Graph Controls

So work with the GraphSharp Graph you need to use the GraphSharp UserControls for WPF. Here is what you need to do where I am using the MainWindowViewModel as just shown to bind against:

<Window x:Class="GraphSharpDemo.MainWindow"        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"        xmlns:graphsharp="clr-namespace:GraphSharp.Controls;assembly=GraphSharp.Controls"        xmlns:local="clr-namespace:GraphSharpDemo"        xmlns:zoom="clr-namespace:WPFExtensions.Controls;assembly=WPFExtensions"                Title="GraphSharpDemo" Height="350" Width="525">        <zoom:ZoomControl  Grid.Row="1"  Zoom="0.2"         ZoomBoxOpacity="0.5" Background="#ff656565">            <local:PocGraphLayout x:Name="graphLayout" Margin="10"        Graph="{Binding Path=Graph}"        LayoutAlgorithmType="{Binding Path=LayoutAlgorithmType, Mode=OneWay}"        OverlapRemovalAlgorithmType="FSA"        HighlightAlgorithmType="Simple" />        </zoom:ZoomControl></Window>

7. Create Templates For Graph Vertices/Edges

Finally all that is left to do, is create some DataTemplates that will show what you want for your custom Graph Vertices/Edges. Here are some examples for the custom Vertices/Edges above

<DataTemplate x:Key="demoTemplate" DataType="{x:Type local:PocVertex}">    <StackPanel Orientation="Horizontal" Margin="5">        <Image x:Name="img" Source="../Images/boy.ico" Width="20" Height="20" />        <TextBlock Text="{Binding Path=ID, Mode=OneWay}" Foreground="White" />    </StackPanel>    <DataTemplate.Triggers>        <DataTrigger Binding="{Binding IsMale}" Value="false">            <Setter TargetName="img" Property="Source"                        Value="../Images/girl.ico" />        </DataTrigger>    </DataTemplate.Triggers></DataTemplate><Style TargetType="{x:Type graphsharp:VertexControl}">    <Setter Property="Template">        <Setter.Value>            <ControlTemplate TargetType="{x:Type graphsharp:VertexControl}">                <Border BorderBrush="White"                         Background="Black"            BorderThickness="2"            CornerRadius="10,10,10,10"            Padding="{TemplateBinding Padding}">                    <ContentPresenter Content="{TemplateBinding Vertex}"                             ContentTemplate="{StaticResource demoTemplate}"/>                    <Border.Effect>                        <DropShadowEffect BlurRadius="2" Color="LightGray"                             Opacity="0.3" Direction="315"/>                    </Border.Effect>                </Border>            </ControlTemplate>        </Setter.Value>    </Setter></Style><Style TargetType="{x:Type graphsharp:EdgeControl}">    <Style.Resources>        <ToolTip x:Key="ToolTipContent">            <StackPanel>                <TextBlock FontWeight="Bold" Text="Edge.ID"/>                <TextBlock Text="{Binding ID}"/>            </StackPanel>        </ToolTip>    </Style.Resources>    <Setter Property="ToolTip" Value="{StaticResource ToolTipContent}"/></Style>

Putting it all together it looks like this:


As always here is a small demo app : GraphSharpDemo.zip

About these ads

46 thoughts on “Pretty Cool Graphs In WPF”

  1. Stone says:

    Hello Sacha,

    as always a vera, very good post. Thank you!

    (Maybe yhou have to fix some links in your article. The links to Graph# are pre-tagged with “sachabarber.net”.)

    Cheers!

    Stone

    Reply
  2. sacha says:

    I will fix that

    Reply
  3. Martin BG says:

    Dude, thank you! I have been looking at GraphSharp occasionally for over a year but have always discounted it in the past because i couldn’t find any resource on it but you have helped clear the way to do some initial playing with this very interesting but under documented tech!

    Reply
    • sacha says:

      Martin Yeah I had to dig into Graph# but its cool to work with

      Reply
  4. Mohamed Amine says:

    Hello,

    Thank you for this wonderful tutorial!

    Well I am having a problem with the Graph# CompoundLayout:
    I can’t find how to make the parent vertices(those with childs) display their content correctly, so I need your help.
    Thank you

    Reply
  5. ITtuition.com says:

    Nice post. Read & Bookmarked :] Thanks!

    Reply
    • sacha says:

      Ituition, glad it helped

      Reply
  6. Igor Zelaya says:

    Great Article for begginners! Hepled me a lot!

    Reply
    • sacha says:

      Igor, glad it helps

      Reply
  7. Hiha says:

    Just came across this post and sample code, and I must say, excellent work! This will help me a lot in wrapping my mind around Graph#

    Reply
    • sacha says:

      Hiha you are welcome, Graph# rocks man

      Reply
  8. pinker says:

    Hi.

    If you want to make an Edge clickable, I would you do?
    (I make the Vertex clickable already).

    Also, if you want to change dinamically the info of a Vertex, how would you make the graph to refresh (for example, if you click on a vertex, swapping from male to female, it should swap also the image based on the trigger)?

    Thanks a lot for this post! It help me a lot.
    regards
    daniela

    Reply
    • sacha says:

      that’s the sort of question you should ask the graph sharp author over at codeplex. I did not write it

      Reply
  9. JanekMi says:

    Hi
    I’m pretty new with WPF but I think I found an error in your example. Label’s aren’t displaying edge’s id’s.
    I think error is in this binding:

    , but I have no idea how to fix this. :-D

    If You could fix it and eventually make a suggestion how to change color of the edge accordingly to some edge parameter I would be very grateful. :-)

    Reply
  10. GrafX says:

    I mean Text=”{Binding ID}” in style to graphsharp:EdgeControl.

    Reply
  11. gomino says:

    Hi,

    Thank you for this excellent how-to.
    But there is a problem with your edge tooltip the binding is not working…

    Can you tell me how to fix it ?

    Reply
    • sacha says:

      Not sure what is wrong there, may have to ask the author of Graph Sharp over at codeplex.

      Reply
  12. Vince says:

    Hi,

    really thanks for the example.
    that’s clear and very useful.

    But now the dl link of the example solution seems down, is it possible to republish it ?

    Thanks to let me know

    Reply
    • sacha says:

      It seems ok now

      Reply
  13. Gregory Stein says:

    Hi.

    First of all thanks for the great example.

    I’m writing some tool for regex build/debug and one of functionalities of it is to provide a graph of the finite automata it produces. For this purpose I’ve chosen graph#.

    I did some modifications to your in order to make it work with my classes. I have question regarding “EfficientSugiyama” layout algorithm. Is it possible to draw smooth lines instead of elbow lines? I mean some sort of B-Splines?

    Thank you!

    Regards, Greg.

    Reply
    • sacha says:

      Greg

      I did not write graph#, you need to ask the author over at its codeplex site.

      Reply
  14. gomino says:

    Problem solved here:
    http://graphsharp.codeplex.com/Thread/View.aspx?ThreadId=70832

    Need the last version of Graphsharp build from source :)

    Reply
  15. sacha says:

    Cool nice one gomino

    Reply
  16. rame0 says:

    Hi, Sacha!
    Could you help me with one problem:
    I did download your code, but when I run the app, I see only black screen… When I move mouse inside the screen, I can see tooltips, but cant see any UI elements at all :(

    Reply
    • sacha says:

      No idea what that could be to be honest

      Reply
  17. rame0 says:

    Not very good … Ok. I’ll have to ask the developers…

    But still thanks! Good post!

    Reply
  18. sunny says:

    You are the greatest.

    Reply
    • sacha says:

      No sure about that, but thanks

      Reply
  19. Tuan Nguyen says:

    Dear Sacha!
    It’s great your tutorial. However, it can’t applied for undirected graph. In your code, I replace BidirectionalGraph with UndirectedGraph, and no error, no graph on layout window. Could you explain?
    Thanks a lot!

    Reply
    • sacha says:

      I am not the author of GraphSharp, so you should ask him at his codeplex site. He should know.

      Reply
  20. Tuan Nguyen says:

    Thanks Sacha!

    Reply
  21. sri says:

    Great tutorial, but could be graphsharp used in Silverlight applications? Can you help me? I’m really new in Silverlight. Thank you.

    Reply
  22. Can says:

    Thank you very much, it is really helpful for us !

    I wonder something about mouse events, when we create a graph we can automatically drag the vertexes or by clicking the empty are we can move the whole graph,but how all of these work ? I want to add multitouch capabilities to graph#, but I don’t know which methods should I call or which events should I fire.

    Can anyone suggest a solution or at least a way for a solution.

    Thanks.

    Reply
  23. Roland Neubert says:

    I have a question:
    when I replace the GraphSharp.Controls.dll with the complete GraphSharp.Controls project, recompile it and and use that created assembly the the binding graphsharp:EdgeControl…ID does not longer work. Do you have an idea what that can cause or how to debug such a not working binding.

    Reply
    • sacha says:

      You would need to ask that sort of question to the chap that did GraphSharp which is not me, ask him at codeplex.

      Reply
  24. Roland Neubert says:

    Thank you for your quick replay – I did that already. What I found for the time being is that the DataItem for the resp. Style changes from DataItem=’PocEdge’ [OK] to DataItem=’MainWindowViewModel’ [faulty].

    Reply
  25. leng says:

    hi, would like to check if you’ve got any idea on how to add in JSON to query from Freebase, at the same time using GraphSharp to present the layout?

    Reply
    • sacha says:

      Well thats really a strange question to do with what is essentially how to lay out a graph in WPF. BUt it would involve creating some service that talked to Freebase via JSON objects being returned which you could then get data from and add as vertices and edges, that is all there is to it really.

      Reply
  26. schorsch says:

    Great tutorial!

    Reply
    • sacha says:

      Thanks

      Reply
  27. Faizan says:

    Hi! I’m new to WPF. Could you please guide me as to how I may get the edges to show data from my custom Edge Type.

    I have weighted graphs, so each Edge type also has an int weight. I would like to show that on the edge…. (not just as a tool tip!)

    Reply
    • sacha says:

      Faizan

      I am not the author of GraphShaarp, you should really ask the author of GraphSharp over at his codeplex site : http://graphsharp.codeplex.com/

      Reply
  28. Faizan says:

    Thanks sacha.
    I know you’re not the author. Its just that you wrote a fantastic tutorial. So I was just looking for pointers.

    Cheers!

    Reply
  29. whatauser says:

    Hi sacha,
    Do you know if it is possible to use Graph# on an asp.net mvc web application?
    I cant find any guidance about it, and I already asked on codeplex but no one answer.
    Thanks, cheers!

    Reply
    • sachabarber says:

      Yeah there is no way you could use graph sharp with asp Mvc, no chance. It’s wpf all the way as such not a chance. Hope that clears it up for you

      Reply
      • whatauser says:

        Ok, thanks sacha! Cheers