Flowchart Layout in WPF SfDiagram

18 Nov 201824 minutes to read

The flowchart layout is a diagrammatic representation of a process, workflow, system, or computer algorithm. Flowcharts use various kinds of symbols to illustrate the different types of actions, and the symbols are connected together with arrows showing the flow direction of a process.

Common flowchart symbols

Different flowchart symbols have different meanings that are used to represent different states in a flowchart. The following table describes the most common flowchart symbols that are used to create a flowchart.

Symbol Built-in resource key in SfDiagram Description
WPF Diagram displays Terminator Symbol Terminator/StartOrEnd Indicates the beginning and ending of the process.
WPF Diagram displays Data Symbol Data Indicates data input or output for a process.
WPF Diagram displays Process Symbol Process Represents an operation or set of operations and data manipulations.
WPF Diagram displays Decision Symbol Decision Shows a branching point where the decision is made to choose one of the two paths.
WPF Diagram displays Document Symbol Document Represents a single document or report in the process.
WPF Diagram displays SubProcess Symbol SubProcess / PredefinedProcess Represents a sequence of actions that combine to perform a specific task that is defined elsewhere. Both keys (SubProcess and PredefinedProcess) map to the same shape; use either name when binding via ShapeMapping.
WPF Diagram displays DirectData Symbol DirectData Represents a collection of information that allows searching, sorting, and filtering. Use for read/write data sources such as databases or files.
WPF Diagram displays StoredData Symbol StoredData Represents a step where data is stored within a process. Use for persistent storage (for example, disk or tape).
WPF Diagram displays ManualInput Symbol ManualInput Represents the manual input of data into a field or step in a process. Use when the value is keyed in by a user. (File renamed to …-symbol.png to match the other entries.)
WPF Diagram displays ManualOperation Symbol ManualOperation Represents an operation in a process that must be done manually, not automatically.
WPF Diagram displays Preparation Symbol Preparation Represents a setup or initialization process to another step in the process.
WPF Diagram displays OnPageReference Symbol OnPageReference Represents a pair of labeled connectors used to link long or confusing lines on a flowchart.
WPF Diagram displays OffPageReference Symbol OffPageReference Represents a labeled connector used to link two flowcharts on different pages.
WPF Diagram displays MultiDocument Symbol MultiDocument Represents multiple documents or reports in the process.
WPF Diagram displays Connector Symbol   Represents a direction of flow from one step to another. It will get created automatically based on the relationship between the parent and child.

NOTE

We have provided some more built-in Shapes as ResourceDictionary. For more Shapes, refer to this page.

<Window.Resources>
    <ResourceDictionary>
        <ResourceDictionary.MergedDictionaries>
            <!--Initialize Shapes-->
            <ResourceDictionary Source="/Syncfusion.SfDiagram.Wpf;component/Resources/BasicShapes.xaml"/>
        </ResourceDictionary.MergedDictionaries>
    </ResourceDictionary>
</Window.Resources>

<local:DataItems x:Key="Dataitems">
<local:ItemInfo Id="1" NodeShape="{StaticResource Terminator}" Width="80" Height="35" Name="Start"/>
<local:ItemInfo Id="2" NodeShape="{StaticResource Data}" Width="90" Height="35" Name="Input">
    <local:ItemInfo.ParentId>
        <local:LabelList>
            <sys:String>1</sys:String>
        </local:LabelList>
    </local:ItemInfo.ParentId>
</local:ItemInfo>
<local:ItemInfo Id="3" NodeShape="{StaticResource Decision}" Width="80" Height="60" Name="Decision?">
    <local:ItemInfo.ParentId>
        <local:LabelList>
            <sys:String>2</sys:String>
        </local:LabelList>
    </local:ItemInfo.ParentId>
</local:ItemInfo>
<local:ItemInfo Id="4" NodeShape="{StaticResource Process}" Width="80" Height="40" Name="Process1">
    <local:ItemInfo.ParentId>
        <local:LabelList>
            <sys:String>3</sys:String>
        </local:LabelList>
    </local:ItemInfo.ParentId>
    <local:ItemInfo.Label>
        <local:LabelList>
                <sys:String>Yes</sys:String>
        </local:LabelList>
    </local:ItemInfo.Label>
</local:ItemInfo>
<local:ItemInfo Id="5" NodeShape="{StaticResource Process}" Width="80" Height="40" Name="Process2">
    <local:ItemInfo.ParentId>
        <local:LabelList>
            <sys:String>3</sys:String>
        </local:LabelList>
    </local:ItemInfo.ParentId>
    <local:ItemInfo.Label>
        <local:LabelList>
            <sys:String>No</sys:String>
        </local:LabelList>
    </local:ItemInfo.Label>
</local:ItemInfo>
<local:ItemInfo Id="6" NodeShape="{StaticResource Data}" Width="90" Height="35" Name="Output">
    <local:ItemInfo.ParentId>
        <local:LabelList>
            <sys:String>5</sys:String>
        </local:LabelList>
    </local:ItemInfo.ParentId>
</local:ItemInfo>
<!--Note: Id=6 and Id=7 share the same Name="Output". Only the Id must be unique;
    Name is for display purposes and is allowed to repeat. The DataSourceSettings
    keying uses Id, not Name.-->
<local:ItemInfo Id="7" NodeShape="{StaticResource Data}" Width="90" Height="35" Name="Output">
    <local:ItemInfo.ParentId>
        <local:LabelList>
            <sys:String>4</sys:String>
        </local:LabelList>
    </local:ItemInfo.ParentId>
</local:ItemInfo>
<local:ItemInfo Id="8" NodeShape="{StaticResource Terminator}" Width="80" Height="35" Name="End">
    <local:ItemInfo.ParentId>
        <local:LabelList>
            <sys:String>6</sys:String>
            <sys:String>7</sys:String>
        </local:LabelList>
    </local:ItemInfo.ParentId>
</local:ItemInfo>
</local:DataItems>
<!--Initializes the Layout-->
<syncfusion:FlowchartLayout x:Key="Layout" Orientation="LeftToRight" 
                            HorizontalSpacing="50" VerticalSpacing="30" 
                            YesBranchDirection="LeftInFlow" 
                            NoBranchDirection="RightInFlow">
</syncfusion:FlowchartLayout>

<!--Initializes the LayoutManager-->
<syncfusion:LayoutManager x:Key="layoutmanager" Layout="{StaticResource Layout}"/>

<!--Initializes the DataSourceSettings -->
<syncfusion:FlowchartDataSourceSettings x:Key="DataSourceSettings" 
                                        DataSource="{StaticResource Dataitems}" 
                                        ParentId="ParentId" Id="Id" 
                                        ShapeMapping="NodeShape" 
                                        WidthMapping="Width" 
                                        HeightMapping="Height" 
                                        ConnectorTextMapping="Label" 
                                        ContentMapping="Name"/>

<!--Initializes the SfDiagram --> 
<syncfusion:SfDiagram x:Name="diagram" Grid.Column="0" 
                      LayoutManager="{StaticResource layoutmanager}" 
                      DataSourceSettings="{StaticResource DataSourceSettings}">
    <syncfusion:SfDiagram.Theme>
        <syncfusion:OfficeTheme/>
    </syncfusion:SfDiagram.Theme>
</syncfusion:SfDiagram>
//Initialize Diagram
SfDiagram diagram = new SfDiagram();

//Initialize Node Collection
diagram.Nodes = new ObservableCollection<NodeViewModel>();           

//Initialize Connector Collection
diagram.Connectors = new ObservableCollection<ConnectorViewModel>();

//ItemInfo must expose a public parameterless constructor so that
//FlowchartDataSourceSettings can instantiate it from the DataSource
//collection. The class below demonstrates the required shape.

//Subscribe to ItemAdded
(diagram.Info as IGraphInfo).ItemAdded += MainWindow_ItemAdded;

//Handler for ItemAdded (placeholder: customize per requirements)
private void MainWindow_ItemAdded(object sender, ItemAddedEventArgs args)
{
    //Perform any per-item initialization here.
}

//Initialize DataSourceSettings for SfDiagram
diagram.DataSourceSettings = new FlowchartDataSourceSettings()
{
    ParentId = "ParentId",
    Id = "Id",
    DataSource = GetData(),
    ConnectorTextMapping = "Label",
    ContentMapping = "Name",
    ShapeMapping = "NodeShape",
    WidthMapping = "Width",
    HeightMapping = "Height"
};

//Initialize LayoutManager
LayoutManager layoutManager = new LayoutManager();

//Initialize Layout for SfDiagram
layoutManager.Layout = new FlowchartLayout()
{
    Orientation = FlowchartOrientation.TopToBottom,
    YesBranchDirection = BranchDirection.LeftInFlow,
    NoBranchDirection = BranchDirection.RightInFlow,             
    HorizontalSpacing = 50,
    VerticalSpacing = 30
};

//Initialize theming style for SfDiagram
diagram.Theme = new OfficeTheme();

//Assign the LayoutManager to the diagram (do not re-initialize the manager here).
diagram.LayoutManager = layoutManager;

//Add the SfDiagram as a child of the main window grid.
WindowGrid.Children.Add(diagram);

//Initializes the DataSource collection
private DataItems GetData()
{
    DataItems itemscollection = new DataItems();
    itemscollection.Add(new ItemInfo()
    {
        Id ="1",
        NodeShape =App.Current.Resources["Terminator"] as string,
        Name = "Start",
        Height =35,
        Width =80
    });
    itemscollection.Add(new ItemInfo()
    {
        Id = "2",
        ParentId =new List<string> { "1" },
        NodeShape = App.Current.Resources["Data"] as string,
        Name = "Input",
        Height = 35,
        Width =90
    });
    itemscollection.Add(new ItemInfo()
    {
        Id = "3", ParentId =new List<string> { "2" },                
        NodeShape = App.Current.Resources["Decision"] as string,
        Name = "Decision?",
        Height =60,
        Width = 80
    });
    itemscollection.Add(new ItemInfo()
    {
        Id = "4",
        ParentId = new List<string> { "3" },
        Label =new List<string> {"Yes" },
        NodeShape = App.Current.Resources["Process"] as string,
        Name = "Process1",
        Height = 40,
        Width = 80
    });
    itemscollection.Add(new ItemInfo()
    {
        Id = "5",
        ParentId = new List<string> { "3" },
        Label = new List<string> { "No" },
        NodeShape = App.Current.Resources["Process"] as string,
        Name = "Process2",
        Height = 40,
        Width = 80
    });
    itemscollection.Add(new ItemInfo()
    {
        Id = "6",
        ParentId = new List<string> { "5" },                
        NodeShape = App.Current.Resources["Data"] as string,
        Name = "Output",
        Height = 35,
        Width = 90
    });
    itemscollection.Add(new ItemInfo()
    {
        Id = "7",
        ParentId = new List<string> { "4" },                
        NodeShape = App.Current.Resources["Data"] as string,
        Name = "Output",
        Height = 35,
        Width = 90
    });
    itemscollection.Add(new ItemInfo()
    {
        Id = "8",
        ParentId = new List<string> { "6","7" },                
        NodeShape =App.Current.Resources["Terminator"] as string,
        Name = "End",
        Height = 35,
        Width = 80
    });
    return itemscollection;
}

//Data Object Class.
//A parameterless constructor is required when ItemInfo instances are
//created via XAML property syntax or by the FlowchartDataSourceSettings.
public class ItemInfo
{
    public ItemInfo()
    {
    }

    public string Name { get; set; }
    public string Id { get; set; }
    public List<string> ParentId { get; set; }
    public string NodeShape { get; set; }       
    public List<string> Label { get; set; }
    public double Width { get; set; }        
    public double Height { get; set; }
}

//Collection to hold the Data Object class
public class DataItems : ObservableCollection<ItemInfo>
{
}

WPF Diagram with Flowchart

Customize flowchart layout orientation

The flow direction of nodes can be customized using the flowchart orientation, either vertically from top to bottom or horizontally from left to right. The Orientation property of the FlowchartLayout class allows you to define the flow direction for a flowchart.

The FlowchartOrientation enum has the following values:

Value Description
TopToBottom Defines the flow orientation as top to bottom. The default value.
LeftToRight Defines the flow orientation as left to right.

TopToBottom orientation

Arranges the element in the layout vertically from top to bottom.

<syncfusion:FlowchartLayout x:Key="Layout" Orientation="TopToBottom"/>
//Initialize LayoutManager
LayoutManager layoutManager = new LayoutManager();
//Initialize Layout for SfDiagram
layoutManager.Layout = new FlowchartLayout()
{
    Orientation = FlowchartOrientation.TopToBottom,            
};

WPF Diagram with FlowChart in Vertical Layout

LeftToRight orientation

Arranges the element in the layout horizontally from left to right.

<syncfusion:FlowchartLayout x:Key="Layout" Orientation="LeftToRight"/>
//Initialize LayoutManager
LayoutManager layoutManager = new LayoutManager();
//Initialize Layout for SfDiagram
layoutManager.Layout = new FlowchartLayout()
{
    Orientation = FlowchartOrientation.LeftToRight,
};

WPF Diagram with FlowChart in Horizontal Layout

Customize the decision output directions

The decision symbol denotes a question that can be answered in binary format (Yes/No, True/False). The output direction of the decision symbol can be controlled by the direction of the “Yes” and “No” branches using the YesBranchDirection and NoBranchDirection properties of the FlowchartLayout class.

The supported BranchDirection enum values are:

Value Description
LeftInFlow Arranges the Yes/No branch to the left of the decision symbol.
RightInFlow Arranges the Yes/No branch to the right of the decision symbol.
SameAsFlow Arranges the Yes/No branch in the same direction as the flow of the decision symbol.

The following table illustrates the behavior:

YesBranchDirection NoBranchDirection TopToBottom LeftToRight
LeftInFlow RightInFlow WPF Diagram displays Decision Output at Left Flow Direction in Vertical WPF Diagram displays Decision Output at Left Flow Direction in Horizontal
RightInFlow LeftInFlow WPF Diagram displays Decision Output at Right Flow Direction in Vertical WPF Diagram displays Decision Output at Right Flow Direction in Horizontal
SameAsFlow RightInFlow WPF Diagram displays Decision Output at Both Direction in Vertical WPF Diagram displays Decision Output at Right Flow Direction in Horizontal
SameAsFlow SameAsFlow WPF Diagram displays Decision Output at Both Direction in Vertical WPF Diagram displays Decision Output at Both Direction in Horizontal

NOTE

If both branch directions are the same, the Yes branch is prioritized.

Custom Yes and No branch values

The decision symbol produces two output branches: a Yes branch and a No branch. If the connector text of an output branch matches a value in the YesBranchValues property of the FlowchartLayout class, it is considered the Yes branch. Similarly, if the connector text matches a value in the NoBranchValues property, it is considered the No branch.

By default, YesBranchValues contains Yes and True; NoBranchValues contains No and False. Any text value can be assigned to a connector to describe the flow, and any string value can be added to YesBranchValues and NoBranchValues. To decide the flow as if/else, the connector text must match a value in YesBranchValues or NoBranchValues. If a connector text matches neither, it falls back to the first matching branch in declaration order.

<syncfusion:FlowchartLayout x:Key="Layout" Orientation="TopToBottom" 
                            YesBranchDirection="LeftInFlow" 
                            NoBranchDirection="RightInFlow"  
                            HorizontalSpacing="50" 
                            VerticalSpacing="30">
    <syncfusion:FlowchartLayout.YesBranchValues>
        <local:LabelList>
            <sys:String>Accept</sys:String>
            <sys:String>Yes</sys:String>
        </local:LabelList>
    </syncfusion:FlowchartLayout.YesBranchValues>
    <syncfusion:FlowchartLayout.NoBranchValues>
        <local:LabelList>
            <sys:String>Reject</sys:String>
            <sys:String>No</sys:String>
        </local:LabelList>
    </syncfusion:FlowchartLayout.NoBranchValues>
</syncfusion:FlowchartLayout>
//Initialize LayoutManager
LayoutManager layoutManager = new LayoutManager();

//Initialize Layout for SfDiagram
layoutManager.Layout = new FlowchartLayout()
{
    Orientation = FlowchartOrientation.TopToBottom,
    YesBranchDirection = BranchDirection.LeftInFlow,
    NoBranchDirection = BranchDirection.RightInFlow,
    YesBranchValues=new List<string> { "Accept","Yes"},
    NoBranchValues=new List<string> { "Reject","No"},
    HorizontalSpacing = 50,
    VerticalSpacing = 30
};

WPF Diagram with CustomFlowChart

Customize vertical and horizontal spacing

Control the spacing between the nodes, both horizontally and vertically, using the HorizontalSpacing and VerticalSpacing properties of the FlowchartLayout class.

<syncfusion:FlowchartLayout x:Key="Layout" HorizontalSpacing="50" VerticalSpacing="30"/>
//Initialize LayoutManager
LayoutManager layoutManager = new LayoutManager();

//Initialize Layout for SfDiagram
layoutManager.Layout = new FlowchartLayout()
{
    HorizontalSpacing = 50,
    VerticalSpacing = 30
};

View sample in GitHub