This topic provides a step by step guidance on how to bind the xamDiagram™ control to hierarchical node data with keys.
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 each of them has a unique string identifier and a collection of keys of its child objects.
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:
Configure the ItemsSource
property
Create the node definitions
Create the connection definitions
The following steps demonstrate how to bind the xamDiagram to hierarchical node data with keys.
Add the sample data class
Add the following Person
class to the code behind. The Person
class has a Name property of type string, an Id property of type int and a Children property set to a list of int. The latter property is used to create the Person-Person relations in the xamDiagram. Note that there is no requirement for the parent-child types to have any relation, and any two types can be used.
In C#:
public class Person : INotifyPropertyChanged
{
public Person(int id, string name) { Id = id; Name = name; }
int _id;
public int Id
{
get { return _id; }
set
{
_id = value;
OnPropertyChanged();
}
}
string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
IList _children;
public IList Children
{
get { return _children; }
set
{
_children = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In VB:
Public Class Person
Implements INotifyPropertyChanged
Public Sub New(id As Integer, name As String)
Id = id
Name = name
End Sub
Private _id As Integer
Public Property Id() As Integer
Get
Return _id
End Get
Set
_id = value
OnPropertyChanged()
End Set
End Property
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Set
_name = value
OnPropertyChanged()
End Set
End Property
Private _children As IList
Public Property Children() As IList
Get
Return _children
End Get
Set
_children = value
OnPropertyChanged()
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler
Private Sub OnPropertyChanged( Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Add the view model class
Add the following list class that the xamDiagram will be bound to:
In C#:
public class FamilyTreeViewModel : INotifyPropertyChanged
{
ObservableCollection<Person> _familyTree;
public ObservableCollection<Person> FamilyTree
{
get { return _familyTree; }
set
{
_familyTree = value;
OnPropertyChanged();
}
}
public FamilyTreeViewModel()
{
var me = new Person(1, "Me");
var dad = new Person(2, "Dad") { Children = new List<int>() { 1 } };
var mom = new Person(3, "Mom") { Children = new List<int>() { 1 } };
var grandpa = new Person(4, "Grandpa") { Children = new List<int>() { 3 } };
var grandma = new Person(5, "Grandma") { Children = new List<int>() { 3 } };
FamilyTree = new ObservableCollection<Person>();
FamilyTree.Add(me);
FamilyTree.Add(dad);
FamilyTree.Add(mom);
FamilyTree.Add(grandpa);
FamilyTree.Add(grandma);
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
In VB:
Public Class FamilyTreeViewModel
Implements INotifyPropertyChanged
Private _familyTree As ObservableCollection(Of Person)
Public Property FamilyTree() As ObservableCollection(Of Person)
Get
Return _familyTree
End Get
Set(value As ObservableCollection(Of Person))
_familyTree = value
OnPropertyChanged()
End Set
End Property
Public Sub New()
Dim [me] = New Person(1, "Me")
Dim dad = New Person(2, "Dad") With { _
.Children = New List(Of Integer)() From { _
1 _
} _
}
Dim mom = New Person(3, "Mom") With { _
.Children = New List(Of Integer)() From { _
1 _
} _
}
Dim grandpa = New Person(4, "Grandpa") With { _
.Children = New List(Of Integer)() From { _
3 _
} _
}
Dim grandma = New Person(5, "Grandma") With { _
.Children = New List(Of Integer)() From { _
3 _
} _
}
FamilyTree = New ObservableCollection(Of Person)()
FamilyTree.Add([me])
FamilyTree.Add(dad)
FamilyTree.Add(mom)
FamilyTree.Add(grandpa)
FamilyTree.Add(grandma)
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private Sub OnPropertyChanged(Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Set the ItemsSource property
Set the DataContext
property to a new instance of the FamilyTreeViewModel
class and bind the ItemsSource to FamilyTree
property.
In XAML:
<ig:XamDiagram ItemsSource="{Binding FamilyTree}">
<ig:XamDiagram.DataContext>
<local:FamilyTreeViewModel/>
</ig:XamDiagram.DataContext>
</ig:XamDiagram>
Usually for each of the data types in the ItemsSource a NodeDefinition is added to the xamDiagram . If one or more types are in an inheritance relationship, the most concrete types have to be specified first. The xamDiagram tries to match the type of each of the data items the TargetType of a node definition. The first node definition whose TargetType returns true to a call to IsAssignableFrom
is selected. That is if the TargetType of a node definition matches exactly or is a parent type of the data item’s type, the node definition will be selected.
In order to use data binding with keys, the node objects must have a unique identifier property to be set as the Key property of the DiagramNode class.
Create a NodeDefinition for the Person
class
Create a NodeDefinition and add it to the NodeDefinitions collection.
Set the TargetType of the NodeDefinition to the Person
type.
Set the KeyMemberPath to Id.This will populate the Key property of the created DiagramNode instances to the value of the Id
property.
Set the DisplayMemberPath to Name . Not specifying a DisplayMemberPath, and not setting a custom DisplayTemplate via the NodeStyle will result 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="{x:Type local:Person}"
KeyMemberPath="Id"
DisplayMemberPath="Name"
ChildKeysMemberPath="Children">
</ig:NodeDefinition>
</ig:XamDiagram.NodeDefinitions>
Create a ConnectionDefinition and add it to the ConnectionDefinitions collection. The connection definitions provide a way to set a custom style for the connection generated by the xamDiagram for parent-child data item relations. Connection definitions are matched by the StartTargetType and EndTargetType properties. For this example set both of these to the Person
type.
Set the ConnectionStyle property to a style targeting DiagramConnection.
In XAML:
<ig:XamDiagram.ConnectionDefinitions>
<ig:ConnectionDefinition
StartTargetType="{x:Type local:Person}"
EndTargetType="{x:Type local:Person}">
<ig:ConnectionDefinition.ConnectionStyle>
<Style TargetType="ig:DiagramConnection">
<Setter Property="ConnectionType" Value="Straight"/>
<Setter Property="Content" Value="Has Child"/>
</Style>
</ig:ConnectionDefinition.ConnectionStyle>
</ig:ConnectionDefinition>
</ig:XamDiagram.ConnectionDefinitions>
Following is the full code for this procedure.
In XAML:
<UserControl x:Class="DiagramDocumentationSamples.HierararchicalKeysData"
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="600" d:DesignWidth="600">
<ig:XamDiagram x:Name="Diagram" ItemsSource="{Binding FamilyTree}">
<ig:XamDiagram.DataContext>
<local:FamilyTreeViewModel/>
</ig:XamDiagram.DataContext>
<ig:XamDiagram.NodeDefinitions>
<ig:NodeDefinition
TargetType="{x:Type local:Person}"
KeyMemberPath="Id"
DisplayMemberPath="Name"
ChildKeysMemberPath="Children">
</ig:NodeDefinition>
</ig:XamDiagram.NodeDefinitions>
<ig:XamDiagram.ConnectionDefinitions>
<ig:ConnectionDefinition
StartTargetType="{x:Type local:Person}"
EndTargetType="{x:Type local:Person}">
<ig:ConnectionDefinition.ConnectionStyle>
<Style TargetType="ig:DiagramConnection">
<Setter Property="ConnectionType" Value="Straight"/>
<Setter Property="Content" Value="Has Child"/>
</Style>
</ig:ConnectionDefinition.ConnectionStyle>
</ig:ConnectionDefinition>
</ig:XamDiagram.ConnectionDefinitions>
<ig:XamDiagram.Layout>
<ig:ForceDirectedGraphDiagramLayout/>
</ig:XamDiagram.Layout>
</ig:XamDiagram>
</UserControl>
In C#:
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows.Controls;
namespace DiagramDocumentationSamples
{
public partial class HierararchicalKeysData : UserControl
{
public HierararchicalKeysData()
{
InitializeComponent();
}
}
public class Person : INotifyPropertyChanged
{
public Person(int id, string name) { Id = id; Name = name; }
int _id;
public int Id
{
get { return _id; }
set
{
_id = value;
OnPropertyChanged();
}
}
string _name;
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
IList _children;
public IList Children
{
get { return _children; }
set
{
_children = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
public class FamilyTreeViewModel : INotifyPropertyChanged
{
ObservableCollection<Person> _familyTree;
public ObservableCollection<Person> FamilyTree
{
get { return _familyTree; }
set
{
_familyTree = value;
OnPropertyChanged();
}
}
public FamilyTreeViewModel()
{
var me = new Person(1, "Me");
var dad = new Person(2, "Dad") { Children = new List<int>() { 1 } };
var mom = new Person(3, "Mom") { Children = new List<int>() { 1 } };
var grandpa = new Person(4, "Grandpa") { Children = new List<int>() { 3 } };
var grandma = new Person(5, "Grandma") { Children = new List<int>() { 3 } };
FamilyTree = new ObservableCollection<Person>();
FamilyTree.Add(me);
FamilyTree.Add(dad);
FamilyTree.Add(mom);
FamilyTree.Add(grandpa);
FamilyTree.Add(grandma);
}
public event PropertyChangedEventHandler PropertyChanged;
void OnPropertyChanged([CallerMemberName] string propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
In VB:
Imports System.Collections
Imports System.Collections.Generic
Imports System.Collections.ObjectModel
Imports System.ComponentModel
Imports System.Runtime.CompilerServices
Imports System.Windows.Controls
Namespace DiagramDocumentationSamples
Public Partial Class HierararchicalKeysData
Inherits UserControl
Public Sub New()
InitializeComponent()
End Sub
End Class
Public Class Person
Implements INotifyPropertyChanged
Public Sub New(id As Integer, name As String)
Id = id
Name = name
End Sub
Private _id As Integer
Public Property Id() As Integer
Get
Return _id
End Get
Set
_id = value
OnPropertyChanged()
End Set
End Property
Private _name As String
Public Property Name() As String
Get
Return _name
End Get
Set
_name = value
OnPropertyChanged()
End Set
End Property
Private _children As IList
Public Property Children() As IList
Get
Return _children
End Get
Set
_children = value
OnPropertyChanged()
End Set
End Property
Public Event PropertyChanged As PropertyChangedEventHandler
Private Sub OnPropertyChanged( Optional propertyName As String = "")
RaiseEvent PropertyChanged(Me, New PropertyChangedEventArgs(propertyName))
End Sub
End Class
Public Class FamilyTreeViewModel
Implements INotifyPropertyChanged
Private _familyTree As ObservableCollection(Of Person)
Public Property FamilyTree() As ObservableCollection(Of Person)
Get
Return _familyTree
End Get
Set(value As ObservableCollection(Of Person))
_familyTree = value
OnPropertyChanged()
End Set
End Property
Public Sub New()
Dim [me] = New Person(1, "Me")
Dim dad = New Person(2, "Dad") With { _
.Children = New List(Of Integer)() From { _
1 _
} _
}
Dim mom = New Person(3, "Mom") With { _
.Children = New List(Of Integer)() From { _
1 _
} _
}
Dim grandpa = New Person(4, "Grandpa") With { _
.Children = New List(Of Integer)() From { _
3 _
} _
}
Dim grandma = New Person(5, "Grandma") With { _
.Children = New List(Of Integer)() From { _
3 _
} _
}
FamilyTree = New ObservableCollection(Of Person)()
FamilyTree.Add([me])
FamilyTree.Add(dad)
FamilyTree.Add(mom)
FamilyTree.Add(grandpa)
FamilyTree.Add(grandma)
End Sub
Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
Private 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.