# Self-Referencing Hierarchy

| RELATED VIDEOS                                                                                                                                                                                                                                                              |                                                                                                                                                                                                                           |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Binding RadGridView to a Self Referencing Hierarchy](http://tv.telerik.com/watch/winforms/binding-radgridview-for-winforms-to-self-referencing-hierarchy)<br>In this video, you will learn how to display a self referencing hierarchy inside of RadGridView for WinForms. | ![WinForms RadGridView Self-Referencing Hierarchy Tutorial](https://www.telerik.com/products/winforms/documentation/assets/8ef3edf6fc8881ef2f7e5031a571bc2d/gridview-hierarchical-grid-self-referencing-hierarchy002.png) |

RadGridView allows you to define a relation that points back to the same table. In the cases when the hierarchical data is build from one type of items you can use a self-referencing RadGridView to display the data. This modes gives you all the functionality a TreeList control would provide, with a lot more.

## Self-Referencing Example

The following example demonstrates how RadGridView displays a hierarchy based on the data provided by the file system where one folder can have files and folders that can have other files and folders, etc.

![WinForms RadGridView Self-Referencing Example](https://www.telerik.com/products/winforms/documentation/assets/d0487ac79568b310d6210147ddee9fbb/gridview-hierarchical-grid-self-referencing-hierarchy001.png)

In order to achieve the look of the RadGridView from the above image, you need to follow these steps:

1\. Create a data source with an appropriate structure where each data record contains `Id` that serves as a unique identifier for the record and `ParentId` that determines the parent of the data record. In our case this is a business object of type `FileSystemItem` that can serve as a folder and as a document.

> important All parent identifiers must be positive numbers.

```C#
public class FileSystemItem
{
    int id;
    string name;
    DateTime creationTime;
    int parentFolderId;
    private string type;

    public int Id
    {
        get
        {
            return id;
        }
        set
        {
            id = value;
        }
    }

    public string FileSystemInfoType
    {
        get
        {
            return type;
        }
        set
        {
            type = value;
        }
    }

    public string Name
    {
        get
        {
            return name;
        }
        set
        {
            name = value;
        }
    }

    public DateTime CreationTime
    {
        get
        {
            return creationTime;
        }
        set
        {
            creationTime = value;
        }
    }

    public int ParentFolderId
    {
        get
        {
            return parentFolderId;
        }
        set
        {
            parentFolderId = value;
        }
    }

    public FileSystemItem(int id, string type, string name, DateTime creationTime, int parentFolderId)
    {
        this.id = id;
        this.type = type;
        this.name = name;
        this.creationTime = creationTime;
        this.parentFolderId = parentFolderId;
    }
}
```

```VB.NET
Public Class FileSystemItem
    Private id_Renamed As Integer
    Private name_Renamed As String
    Private creationTime_Renamed As Date
    Private parentFolderId_Renamed As Integer

    Private type As String

    Public Property Id() As Integer
        Get
            Return id_Renamed
        End Get
        Set(ByVal value As Integer)
            id_Renamed = value
        End Set
    End Property

    Public Property FileSystemInfoType() As String
        Get
            Return type
        End Get
        Set(ByVal value As String)
            type = value
        End Set
    End Property

    Public Property Name() As String
        Get
            Return name_Renamed
        End Get
        Set(ByVal value As String)
            name_Renamed = value
        End Set
    End Property

    Public Property CreationTime() As Date
        Get
            Return creationTime_Renamed
        End Get
        Set(ByVal value As Date)
            creationTime_Renamed = value
        End Set
    End Property

    Public Property ParentFolderId() As Integer
        Get
            Return parentFolderId_Renamed
        End Get
        Set(ByVal value As Integer)
            parentFolderId_Renamed = value
        End Set
    End Property

    Public Sub New(ByVal id As Integer, ByVal type As String, ByVal name As String, ByVal creationTime As Date, ByVal parentFolderId As Integer)
        Me.id_Renamed = id
        Me.type = type
        Me.name_Renamed = name
        Me.creationTime_Renamed = creationTime
        Me.parentFolderId_Renamed = parentFolderId
    End Sub
End Class
```

2\. Fill a BindingList with objects of type FileSystemItem. The content of the list will depend on the content of the "C:\Program Files (x86)\Telerik" folder:

```C#
BindingList<FileSystemItem> list = new BindingList<FileSystemItem>();
int fileFolderIndex = 0;

public void GetFilesAndFolders(string dir, int parentId)
{
    DirectoryInfo di = new DirectoryInfo(dir);
    FileInfo[] rgFiles = di.GetFiles();
    foreach (FileInfo fi in rgFiles)
    {
        fileFolderIndex++;
        list.Add(new FileSystemItem(fileFolderIndex, "File", fi.Name, fi.CreationTime, parentId));
    }

    DirectoryInfo[] dirs = di.GetDirectories();
    foreach (DirectoryInfo d in dirs)
    {
        fileFolderIndex++;
        list.Add(new FileSystemItem(fileFolderIndex, "Folder", d.Name, d.CreationTime, parentId));
        GetFilesAndFolders(d.FullName, fileFolderIndex);
    }
}
```

```VB.NET
Private list As New BindingList(Of FileSystemItem)()
Private fileFolderIndex As Integer = 0

Public Sub GetFilesAndFolders(ByVal dir As String, ByVal parentId As Integer)
    Dim di As New DirectoryInfo(dir)
    Dim rgFiles() As FileInfo = di.GetFiles()
    For Each fi As FileInfo In rgFiles
        fileFolderIndex += 1
        list.Add(New FileSystemItem(fileFolderIndex, "File", fi.Name, fi.CreationTime, parentId))
    Next fi

    Dim dirs() As DirectoryInfo = di.GetDirectories()
    For Each d As DirectoryInfo In dirs
        fileFolderIndex += 1
        list.Add(New FileSystemItem(fileFolderIndex, "Folder", d.Name, d.CreationTime, parentId))
        GetFilesAndFolders(d.FullName, fileFolderIndex)
    Next d
End Sub
```

3\. The most important step of this example - setting up the self-referencing mode of RadGridView. To do this, you should call the **AddSelfReference** method of the **Relations** collection passing the template that should reflect the structure of the business object and the properties that should determine the parent-child relation:

```C#
this.radGridView1.Relations.AddSelfReference(this.radGridView1.MasterTemplate, "Id", "ParentFolderId");
this.radGridView1.DataSource = list;
```

```VB.NET
Me.RadGridView1.Relations.AddSelfReference(Me.RadGridView1.MasterTemplate, "Id", "ParentFolderId")
Me.RadGridView1.DataSource = list
```

4\. Hide the columns that are not useful to your clients. These columns in our case are `Id`, `ParentFolderId` and `FileSystemInfoType`:

```C#
this.radGridView1.Columns["Id"].IsVisible = false;
this.radGridView1.Columns["ParentFolderId"].IsVisible = false;
this.radGridView1.Columns["FileSystemInfoType"].IsVisible = false;
```

```VB.NET
Me.RadGridView1.Columns("Id").IsVisible = False
Me.RadGridView1.Columns("ParentFolderId").IsVisible = False
Me.RadGridView1.Columns("FileSystemInfoType").IsVisible = False
```

5\. Last, but not least, you may want to show different images depending on the actual file system types. To do this, you should handle the **CellFormatting** event, check if the `FileSystemInfoType` is *File* or *Folder* and set the appropriate image accordingly:

```C#

// Getting the images from the resources of the project
Image documentImage = SamplesCS.Properties.Resources.Document;
Image folderImage = SamplesCS.Properties.Resources.Folder;

void radGridView1_CellFormatting(object sender, Telerik.WinControls.UI.CellFormattingEventArgs e)
{
    GridDataCellElement dataCell = e.CellElement as GridDataCellElement;

    if (dataCell.ColumnInfo.Name == "Name")
    {
        GridViewDataRowInfo dataRow = dataCell.RowInfo as GridViewDataRowInfo;
        if (dataRow != null)
        {
            dataCell.ImageAlignment = ContentAlignment.MiddleLeft;

            string valueType = Convert.ToString(dataRow.Cells["FileSystemInfoType"].Value).ToUpperInvariant();

            if (valueType.Contains("FILE"))
            {
                dataCell.Image = documentImage;
            }
            else
            {
                dataCell.Image = folderImage;
            }

            dataCell.TextImageRelation = TextImageRelation.ImageBeforeText;
        }
    }
    else
    {
        dataCell.ResetValue(LightVisualElement.ImageProperty, Telerik.WinControls.ValueResetFlags.Local);
        dataCell.ResetValue(LightVisualElement.ImageAlignmentProperty, Telerik.WinControls.ValueResetFlags.Local);
        dataCell.ResetValue(LightVisualElement.TextImageRelationProperty, Telerik.WinControls.ValueResetFlags.Local);
        dataCell.ResetValue(LightVisualElement.ImageLayoutProperty, Telerik.WinControls.ValueResetFlags.Local);
    }
}
```

```VB.NET

' Getting the images from the resources of the project
Private documentImage As Image = My.Resources.Document
Private folderImage As Image = My.Resources.Folder

Private Sub radGridView1_CellFormatting(ByVal sender As Object, ByVal e As Telerik.WinControls.UI.CellFormattingEventArgs)
    Dim dataCell As GridDataCellElement = TryCast(e.CellElement, GridDataCellElement)

    If dataCell.ColumnInfo.Name = "Name" Then
        Dim dataRow As GridViewDataRowInfo = TryCast(dataCell.RowInfo, GridViewDataRowInfo)
        If dataRow IsNot Nothing Then
            dataCell.ImageAlignment = ContentAlignment.MiddleLeft

            Dim valueType As String = Convert.ToString(dataRow.Cells("FileSystemInfoType").Value).ToUpperInvariant()

            If valueType.Contains("FILE") Then
                dataCell.Image = documentImage
            Else
                dataCell.Image = folderImage
            End If

            dataCell.TextImageRelation = TextImageRelation.ImageBeforeText
        End If
    Else
        dataCell.ResetValue(LightVisualElement.ImageProperty, Telerik.WinControls.ValueResetFlags.Local)
        dataCell.ResetValue(LightVisualElement.ImageAlignmentProperty, Telerik.WinControls.ValueResetFlags.Local)
        dataCell.ResetValue(LightVisualElement.TextImageRelationProperty, Telerik.WinControls.ValueResetFlags.Local)
        dataCell.ResetValue(LightVisualElement.ImageLayoutProperty, Telerik.WinControls.ValueResetFlags.Local)
    End If
End Sub
```

It is possible to put the self-reference expander in any column by setting the **SelfReferenceExpanderColumn** property of the **MasterTemplate**:

![WinForms RadGridView SelfReferenceExpanderColumn](https://www.telerik.com/products/winforms/documentation/assets/a508dfc321474382150d8119f11a298c/gridview-hierarchical-grid-self-referencing-hierarchy003.png)

```C#
this.radGridView1.MasterTemplate.SelfReferenceExpanderColumn = this.radGridView1.Columns["ParentFolderId"];
```

```VB.NET
Me.RadGridView1.MasterTemplate.SelfReferenceExpanderColumn = Me.RadGridView1.Columns("ParentFolderId")
```

> note You can use the **TableElement.ShowSelfReferenceLines** property to show lines that are connecting the parent/child rows.

## See Also

* [Binding to Hierarchical Data Automatically](https://www.telerik.com/products/winforms/documentation/controls/gridview/hierarchical-grid/binding-to-hierarchical-data-automatically)

* [Binding to Hierarchical Data Programmatically](https://www.telerik.com/products/winforms/documentation/controls/gridview/hierarchical-grid/binding-to-hierarchical-data-programmatically)

* [Binding to Hierarchical Data](https://www.telerik.com/products/winforms/documentation/controls/gridview/hierarchical-grid/binding-to-hierarchical-data)

* [Creating hierarchy using an XML data source](https://www.telerik.com/products/winforms/documentation/controls/gridview/hierarchical-grid/creating-hierarchy-using-an-xml-data-source)

* [Hierarchy of one to many relations](https://www.telerik.com/products/winforms/documentation/controls/gridview/hierarchical-grid/hierarchy-of-one-to-many-relations)

* [Load-On-Demand Hierarchy](https://www.telerik.com/products/winforms/documentation/controls/gridview/hierarchical-grid/load-on-demand-hierarchy)

* [Object Relational Hierarchy Mode](https://www.telerik.com/products/winforms/documentation/controls/gridview/hierarchical-grid/object-relational-hierarchy-mode)

* [Tutorial Binding to Hierarchical Data](https://www.telerik.com/products/winforms/documentation/controls/gridview/hierarchical-grid/tutorial-binding-to-hierarchical-data)
