This topic provides a step by step guidance on how to bind the xamDiagram™ control to data where input data objects represent nodes and connections. Each of the node objects has a property of type object
that represents a unique identifier and each of the connection objects has two properties holding the identifiers of the two node objects representing its start and end nodes.
The following topics are prerequisites to understanding this topic:
The following procedure demonstrates how to bind the xamDiagram to data where input data objects represent nodes and connections. Each of the node objects has a property of type object
that represents a unique identifier and each of the connection objects has two properties holding the identifiers of the two node objects representing its start and end nodes.
The following screenshot is a preview of the result.
To complete the procedure, you need the following:
A WPF application with an empty xamDiagram added to a page
The Layout property of the xamDiagram set to an instance of the ForceDirectedGraphDiagramLayout
Following is a conceptual overview of the process:
Setting the ItemsSource and ConnectionSource
Creating the node definitions
Creating the connection definitions
The following steps demonstrate how to bind the xamDiagram to nodes and connections data with keys, building a diagram of the Waterflow software development process.
Add the sample node data class
Add the following Activity
class to the code behind. The Activity
represents the node object and has a single string property called Key
.
In C#:
public class Activity : INotifyPropertyChanged
{
public Activity(string name) { Key = name; }
private string _key;
public string Key {
get { return _key; }
set
{
_key = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In VB:
Public Class Activity
Implements INotifyPropertyChanged
Public Sub New(name As String)
Key = name
End Sub
Private _key As String
Public Property Key() As String
Get
Return _key
End Get
Set
_key = value
OnPropertyChanged()
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler
Protected Sub OnPropertyChanged( Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Add the sample connection class
Add the following ActivityRelation
class to the code behind. The ActivityRelation
class represents a directed connection between two Activity
instances. It has two string properties that are set to the start and end activities’ keys.
In C#:
public class ActivityRelation : INotifyPropertyChanged
{
public ActivityRelation(string from, string to)
{
StartKey = from;
EndKey = to;
}
private string _startKey;
public string StartKey
{
get { return _startKey; }
set
{
_startKey = value;
OnPropertyChanged();
}
}
private string _endKey;
public string EndKey
{
get { return _endKey; }
set
{
_endKey = value;
OnPropertyChanged();
}
}
public override string ToString()
{
return "";
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In VB:
Public Class ActivityRelation
Implements INotifyPropertyChanged
Public Sub New(from As String, [to] As String)
StartKey = from
EndKey = [to]
End Sub
Private _startKey As String
Public Property StartKey() As String
Get
Return _startKey
End Get
Set
_startKey = value
OnPropertyChanged()
End Set
End Property
Private _endKey As String
Public Property EndKey() As String
Get
Return _endKey
End Get
Set
_endKey = value
OnPropertyChanged()
End Set
End Property
Public Overrides Function ToString() As String
Return ""
End Function
Public Event PropertyChanged As PropertyChangedEventHandler
Protected Sub OnPropertyChanged( Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Add the data items
Add the following WaterFlowViewModel
class which exposes two list properties – for nodes and for connections and is automatically populated with some sample data.
In C#:
public class WaterFlowViewModel : INotifyPropertyChanged
{
public WaterFlowViewModel()
{
Activities = new ObservableCollection<Activity>()
{
new Activity("Requirements"),
new Activity("Design"),
new Activity("Construction"),
new Activity("Integration"),
new Activity("Testing"),
new Activity("Installation"),
new Activity("Maintenance")
};
Relations = new ObservableCollection<ActivityRelation>()
{
new ActivityRelation("Requirements", "Design"),
new ActivityRelation("Design", "Construction"),
new ActivityRelation("Construction", "Integration"),
new ActivityRelation("Integration", "Testing"),
new ActivityRelation("Testing", "Installation"),
new ActivityRelation("Installation", "Maintenance"),
};
}
private IList<Activity> _activities;
public IList<Activity> Activities
{
get { return _activities; }
set
{
_activities = value;
OnPropertyChanged();
}
}
private IList<ActivityRelation> _relations;
public IList<ActivityRelation> Relations
{
get { return _relations; }
set
{
_relations = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In VB:
Public Class WaterFlowViewModel
Implements INotifyPropertyChanged
Public Sub New()
Activities = New ObservableCollection(Of Activity)() From { _
New Activity("Requirements"), _
New Activity("Design"), _
New Activity("Construction"), _
New Activity("Integration"), _
New Activity("Testing"), _
New Activity("Installation"), _
New Activity("Maintenance") _
}
Relations = New ObservableCollection(Of ActivityRelation)() From { _
New ActivityRelation("Requirements", "Design"), _
New ActivityRelation("Design", "Construction"), _
New ActivityRelation("Construction", "Integration"), _
New ActivityRelation("Integration", "Testing"), _
New ActivityRelation("Testing", "Installation"), _
New ActivityRelation("Installation", "Maintenance") _
}
End Sub
Private _activities As IList(Of Activity)
Public Property Activities() As IList(Of Activity)
Get
Return _activities
End Get
Set(value As IList(Of Activity))
_activities = value
OnPropertyChanged()
End Set
End Property
Private _relations As IList(Of ActivityRelation)
Public Property Relations() As IList(Of ActivityRelation)
Get
Return _relations
End Get
Set(value As IList(Of ActivityRelation))
_relations = value
OnPropertyChanged()
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Set the DataContext of the XamDiagram
Set the diagram’s DataContext
property to an instance of the WaterFlowViewModel
class.
In XAML:
<ig:XamDiagram>
<ig:XamDiagram.DataContext>
<local:WaterFlowViewModel/>
</ig:XamDiagram.DataContext>
</ig:XamDiagram>
Set the ItemsSource property
Bind the ItemsSource to the Articles
property of the WaterFlowViewModel
data context.
In XAML:
ItemsSource="{Binding Activities}"
Set the ConnectionsSource property
Bind the ConnectionsSource to the Relations
property of the WaterFlowViewModel
data context.
In XAML:
ConnectionsSource="{Binding Relations}"
For each of the data types in the ItemsSource a NodeDefinition is usually added to the xamDiagram . Specify the most concrete types first if one or more types are in an inheritance relationship. The xamDiagram tries to match the type of each of the data items in the TargetType of a node definition. The first node definition whose TargetType returns true from a call to IsAssignableFrom
is selected. That is if the TargetType of the node definition matches exactly, or is a parent type of the data item’s type; otherwise, the node definition is selected.
In order to use data binding with keys, the node objects must have a string property with valid value for the Key property of the DiagramNode class.
Create a NodeDefinition for the Activity
class and add it to the NodeDefinitions collection.
Set the TargetType of the NodeDefinition to the Activity
type.
Set the KeyMemberPath to Key. This will populate the Name property of the created DiagramNode instances to the value of the Key property.
Set the DisplayMemberPath to Key. Not specifying a DisplayMemberPath, and not setting a custom DisplayTemplate via the NodeStyle, the results in the ToString
method displayed as the nodes’ content.
Set the NodeStyle (optional)
Using the NodeStyle property you can set the style to be applied to all DiagramNode
objects matched by the node definition. This gives you the opportunity to easily customize the nodes created for a certain data type.
In XAML:
<ig:XamDiagram.NodeDefinitions>
<ig:NodeDefinition
TargetType="local:Activity"
KeyMemberPath="Key"
DisplayMemberPath="Key">
<ig:NodeDefinition.NodeStyle>
<Style TargetType="ig:DiagramNode">
<Setter Property="ConnectionPoints">
<Setter.Value>
<ig:DiagramConnectionPointCollection>
<ig:DiagramConnectionPoint Name="Top" Position="0.5, 0"/>
<ig:DiagramConnectionPoint Name="Right" Position="1, 0.5"/>
</ig:DiagramConnectionPointCollection>
</Setter.Value>
</Setter>
</Style>
</ig:NodeDefinition.NodeStyle>
</ig:NodeDefinition>
</ig:XamDiagram.NodeDefinitions>
When supplying separate connection data objects, use an instance of ConnectionSourceDefinition in the diagram’s ConnectionDefinitions. This type of connection definition describes what connection to create for each data items matching the definition’s TargetType. In order for such a connection to have its StartNodeKey and EndNodeKey properties correctly populated, the connection definition’s StartNodeKeyMemberPath and EndNodeKeyMemberPath properties must be set to the names of the properties holding the identifiers of the start/end node data objects.
Create a ConnectionSourceDefinition and add it to the ConnectionDefinitions collection.
Set the TargetType to the ActivityRelation
type.
Set the StartNodeKeyMemberPath to "StartKey". Set the EndNodeKeyMemberPath to "EndKey".
Set the ConnectionStyle (optional)
You can customize the connections created for a particular data type by setting the ConnectionStyle property to a style targeting DiagramConnection. You can specify a setting for the DisplayTemplate property and apply a template setting the DataContext
where the data object will be.
In XAML:
<ig:XamDiagram.ConnectionDefinitions>
<ig:ConnectionSourceDefinition
TargetType="local:ActivityRelation"
StartNodeKeyMemberPath="StartKey"
EndNodeKeyMemberPath="EndKey"/>
</ig:XamDiagram.ConnectionDefinitions>
Following is the full code for this procedure.
In XAML:
<UserControl x:Class="DiagramDocumentationSamples.NodesConnectionsKeysData"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:ig="http://schemas.infragistics.com/xaml"
xmlns:local="clr-namespace:DiagramDocumentationSamples"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<ig:XamDiagram ConnectionsSource="{Binding Relations}" ItemsSource="{Binding Activities}">
<ig:XamDiagram.DataContext>
<local:WaterFlowViewModel/>
</ig:XamDiagram.DataContext>
<ig:XamDiagram.NodeDefinitions>
<ig:NodeDefinition
TargetType="local:Activity"
KeyMemberPath="Key"
DisplayMemberPath="Key">
<ig:NodeDefinition.NodeStyle>
<Style TargetType="ig:DiagramNode">
<Setter Property="ConnectionPoints">
<Setter.Value>
<ig:DiagramConnectionPointCollection>
<ig:DiagramConnectionPoint Name="Top" Position="0.5, 0"/>
<ig:DiagramConnectionPoint Name="Right" Position="1, 0.5"/>
</ig:DiagramConnectionPointCollection>
</Setter.Value>
</Setter>
</Style>
</ig:NodeDefinition.NodeStyle>
</ig:NodeDefinition>
</ig:XamDiagram.NodeDefinitions>
<ig:XamDiagram.ConnectionDefinitions>
<ig:ConnectionSourceDefinition
TargetType="local:ActivityRelation"
StartNodeKeyMemberPath="StartKey"
EndNodeKeyMemberPath="EndKey"/>
</ig:XamDiagram.ConnectionDefinitions>
<ig:XamDiagram.Layout>
<ig:ForceDirectedGraphDiagramLayout/>
</ig:XamDiagram.Layout>
</ig:XamDiagram>
</UserControl>
In C#:
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Controls;
namespace DiagramDocumentationSamples
{
public partial class NodesConnectionsKeysData : UserControl
{
public NodesConnectionsKeysData()
{
InitializeComponent();
}
}
public class WaterFlowViewModel : INotifyPropertyChanged
{
public WaterFlowViewModel()
{
Activities = new ObservableCollection<Activity>()
{
new Activity("Requirements"),
new Activity("Design"),
new Activity("Construction"),
new Activity("Integration"),
new Activity("Testing"),
new Activity("Installation"),
new Activity("Maintenance")
};
Relations = new ObservableCollection<ActivityRelation>()
{
new ActivityRelation("Requirements", "Design"),
new ActivityRelation("Design", "Construction"),
new ActivityRelation("Construction", "Integration"),
new ActivityRelation("Integration", "Testing"),
new ActivityRelation("Testing", "Installation"),
new ActivityRelation("Installation", "Maintenance"),
};
}
private IList<Activity> _activities;
public IList<Activity> Activities
{
get { return _activities; }
set
{
_activities = value;
OnPropertyChanged();
}
}
private IList<ActivityRelation> _relations;
public IList<ActivityRelation> Relations
{
get { return _relations; }
set
{
_relations = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class Activity : INotifyPropertyChanged
{
public Activity(string name) { Key = name; }
private string _key;
public string Key
{
get { return _key; }
set
{
_key = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ActivityRelation : INotifyPropertyChanged
{
public ActivityRelation(string from, string to)
{
StartKey = from;
EndKey = to;
}
private string _startKey;
public string StartKey
{
get { return _startKey; }
set
{
_startKey = value;
OnPropertyChanged();
}
}
private string _endKey;
public string EndKey
{
get { return _endKey; }
set
{
_endKey = value;
OnPropertyChanged();
}
}
public override string ToString()
{
return "";
}
public event PropertyChangedEventHandler PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In VB:
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Imports System.Windows.Controls
Namespace DiagramDocumentationSamples
Public Partial Class NodesConnectionsKeysData
Inherits UserControl
Public Sub New()
InitializeComponent()
End Sub
End Class
Public Class WaterFlowViewModel
Implements INotifyPropertyChanged
Public Sub New()
Activities = New ObservableCollection(Of Activity)() From { _
New Activity("Requirements"), _
New Activity("Design"), _
New Activity("Construction"), _
New Activity("Integration"), _
New Activity("Testing"), _
New Activity("Installation"), _
New Activity("Maintenance") _
}
Relations = New ObservableCollection(Of ActivityRelation)() From { _
New ActivityRelation("Requirements", "Design"), _
New ActivityRelation("Design", "Construction"), _
New ActivityRelation("Construction", "Integration"), _
New ActivityRelation("Integration", "Testing"), _
New ActivityRelation("Testing", "Installation"), _
New ActivityRelation("Installation", "Maintenance") _
}
End Sub
Private _activities As IList(Of Activity)
Public Property Activities() As IList(Of Activity)
Get
Return _activities
End Get
Set(value As IList(Of Activity))
_activities = value
OnPropertyChanged()
End Set
End Property
Private _relations As IList(Of ActivityRelation)
Public Property Relations() As IList(Of ActivityRelation)
Get
Return _relations
End Get
Set(value As IList(Of ActivityRelation))
_relations = value
OnPropertyChanged()
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Public Class Activity
Implements INotifyPropertyChanged
Public Sub New(name As String)
Key = name
End Sub
Private _key As String
Public Property Key() As String
Get
Return _key
End Get
Set(value As String)
_key = value
OnPropertyChanged()
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Public Class ActivityRelation
Implements INotifyPropertyChanged
Public Sub New(from As String, [to] As String)
StartKey = from
EndKey = [to]
End Sub
Private _startKey As String
Public Property StartKey() As String
Get
Return _startKey
End Get
Set(value As String)
_startKey = value
OnPropertyChanged()
End Set
End Property
Private _endKey As String
Public Property EndKey() As String
Get
Return _endKey
End Get
Set(value As String)
_endKey = value
OnPropertyChanged()
End Set
End Property
Public Overrides Function ToString() As String
Return ""
End Function
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Protected Sub OnPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
End Namespace
The following topics provide additional information related to this topic.