GraphSharp Tutorials

本文转自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

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

  2. sacha  says:

    I will fix that

  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!

  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

  5. ITtuition.com  says:

    Nice post. Read & Bookmarked :] Thanks!

  6. Igor Zelaya  says:

    Great Article for begginners! Hepled me a lot!

  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#

  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

    • sacha  says:

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

  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. :-)

  10. GrafX  says:

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

  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 ?

    • sacha  says:

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

  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

  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.

  14. gomino  says:

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

    Need the last version of Graphsharp build from source :)

  15. sacha  says:

    Cool nice one gomino

  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 :(

  17. rame0  says:

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

    But still thanks! Good post!

  18. sunny  says:

    You are the greatest.

  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!

    • sacha  says:

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

  20. Tuan Nguyen  says:

    Thanks Sacha!

  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.

  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.

  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.

    • 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.

  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].

  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?

    • 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.

  26. schorsch  says:

    Great tutorial!

  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!)

  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!

  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!

    • 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



  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值