Back to Devexpress

Unbound Columns

windowsforms-17831-controls-and-libraries-tree-list-feature-center-data-binding-unbound-columns.md

latest18.2 KB
Original Source

Unbound Columns

  • Jul 14, 2022
  • 9 minutes to read

Unbound columns allow you to display custom data in the Tree List control. These columns are not bound to fields in the data source, and data for these columns needs to be provided using expressions or a dedicated event.

Bound and Unbound Columns

Tree List supports two types of columns: bound and unbound.

Bound columns obtain their data from a control’s data source (TreeList.DataSource and TreeList.DataMember). These columns’ TreeListColumn.FieldName properties refer to fields that exist in the data source.

In some cases, the data source does not provide the values you wish to display in the Tree List. For instance, you may want to display values calculated according to a formula based on other column values. Unbound columns address these tasks.

To make a column unbound, do the following:

  • Set its UnboundDataType property to the type of data the column will display.

  • Set the unbound column’s TreeListColumn.FieldName property to a unique field name.

  • C#

  • VB.NET

csharp
TreeListColumn unboundCol1 = new TreeListColumn();
unboundCol1.UnboundDataType = typeof(int);
unboundCol1.FieldName = "MyUnboundColumn1";
treeList1.Columns.Add(unboundCol1);
unboundCol1.Visible = true;
vb
Dim unboundCol1 As TreeListColumn = New TreeListColumn()
unboundCol1.UnboundDataType = GetType(Int32)
unboundCol1.FieldName = "MyUnboundColumn1"
TreeList1.Columns.Add(unboundCol1)
unboundCol1.Visible = true

Unbound Columns’ Data

Provide data for unbound columns using one of two approaches:

Edit or Read-Only Mode

All unbound columns are editable by default. The TreeListOptionsColumn.AllowEdit or TreeListOptionsColumn.ReadOnly settings allow you to disable data edit operations.

To save changes made by end-users in unbound columns, an unbound column must be populated with the TreeList.CustomUnboundColumnData event, but not using expressions. This event’s IsGetData and IsSetData parameters determine whether you should provide or save the column’s data.

Note

Unbound columns are supported in the following binding modes:

Unbound columns are not supported in other binding modes, which include:

Reload Data in Unbound Columns

To reload data in unbound columns and redraw the control on-screen, use the following methods:

The control also reloads data in unbound columns when you sort or filter data.

Example 1

This example demonstrates how to create an editable unbound column. The example uses a simple cache implementation within the CustomUnboundColumnData event handler to fetch custom data faster.

csharp
using DevExpress.XtraTreeList.Columns;

private void CreateUnboundColumn() {
    TreeListColumn column = treeList1.Columns.AddVisible("UnboundColumn");
    column.UnboundDataType = typeof(string);
}

Dictionary<int, string> storage = new Dictionary<int, string>();
private void treeList1_CustomUnboundColumnData(object sender, DevExpress.XtraTreeList.TreeListCustomColumnDataEventArgs e) {
    if(e.Column.FieldName == "UnboundColumn") {
        if(e.IsGetData)
            if(storage.ContainsKey(e.NodeID))
                e.Value = storage[e.NodeID];
            else
                e.Value = storage[e.NodeID] = string.Format("Unbound value {0}", e.NodeID);
        if(e.IsSetData)
            storage[e.NodeID] = e.Value.ToString();
    }
}
vb
Imports DevExpress.XtraTreeList.Columns

Private Sub CreateUnboundColumn()
    Dim column As TreeListColumn = treeList1.Columns.AddVisible("UnboundColumn")
    column.UnboundDataType = GetType(String)
End Sub

Private storage As New Dictionary(Of Integer, String)()
Private Sub treeList1_CustomUnboundColumnData(ByVal sender As Object, ByVal e As DevExpress.XtraTreeList.TreeListCustomColumnDataEventArgs)
    If e.Column.FieldName = "UnboundColumn" Then
        If e.IsGetData Then
            If storage.ContainsKey(e.NodeID) Then
                e.Value = storage(e.NodeID)
            Else
                storage(e.NodeID) = String.Format("Unbound value {0}", e.NodeID)
                e.Value = storage(e.NodeID)
            End If
        End If
        If e.IsSetData Then
            storage(e.NodeID) = e.Value.ToString()
        End If
    End If
End Sub

Example 2

This example creates a “Change from Previous Year” read-only unbound column in the TreeList control and populates this column with data using the TreeList.CustomUnboundColumnData event.

View Example

csharp
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using DevExpress.XtraEditors;
using DevExpress.Skins;
using DevExpress.LookAndFeel;
using DevExpress.UserSkins;
using DevExpress.XtraTreeList.Columns;

namespace TreeList_UnboundDataViaEvent {
    public partial class Form1 : XtraForm {
        public Form1() {
            InitializeComponent();
            InitTreeList();
        }

        void InitTreeList() {
            treeList1.DataSource = SalesDataGenerator.CreateData();

            // Create and customize an unbound column.
            TreeListColumn unbColumnMarchChange = new TreeListColumn();
            unbColumnMarchChange.UnboundDataType = typeof(decimal);
            unbColumnMarchChange.Visible = true;
            unbColumnMarchChange.OptionsColumn.AllowEdit = false;
            unbColumnMarchChange.FieldName = "ChangeFromPrevYear";
            unbColumnMarchChange.Caption = "Change from Previous Year";
            unbColumnMarchChange.Format.FormatType = DevExpress.Utils.FormatType.Numeric;
            unbColumnMarchChange.Format.FormatString = "p2";
            tlBandThisYear.Columns.Add(unbColumnMarchChange);
            // Change the appearance settings after the column is added to the TreeList.
            unbColumnMarchChange.AppearanceHeader.Font = new Font(unbColumnMarchChange.AppearanceHeader.Font, FontStyle.Bold);
            unbColumnMarchChange.AppearanceCell.BackColor = Color.LightYellow;
            // Subcribe to the event that provides data for unbound columns.
            treeList1.CustomUnboundColumnData += TreeList1_CustomUnboundColumnData;
            // Resize columns proportionally.
            treeList1.ForceInitialize();
            treeList1.BestFitColumns();
        }

        private void TreeList1_CustomUnboundColumnData(object sender, DevExpress.XtraTreeList.TreeListCustomColumnDataEventArgs e) {
            if(e.IsGetData && e.Column.FieldName == "ChangeFromPrevYear") {
                SalesData currentRow = e.Row as SalesData;
                if (currentRow == null) return;
                e.Value = (currentRow.MarchSales - currentRow.MarchSalesPrev) / currentRow.MarchSalesPrev;
            }
        }
    }

    public class SalesData {
        public SalesData(int id, int regionId, string region, decimal marchSales, decimal marchSalesPrev) {
            ID = id;
            RegionID = regionId;
            Region = region;
            MarchSales = marchSales;
            MarchSalesPrev = marchSalesPrev;
        }
        public int ID { get; set; }
        public int RegionID { get; set; }
        public string Region { get; set; }
        public decimal MarchSales { get; set; }
        public decimal MarchSalesPrev { get; set; }

    }
    public class SalesDataGenerator {
        public static List<SalesData> CreateData() {
            List<SalesData> sales = new List<SalesData>();
            sales.Add(new SalesData(0, -1, "Western Europe", 30540, 33000));
            sales.Add(new SalesData(1, 0, "Austria", 22000, 20000));
            sales.Add(new SalesData(2, 0, "Belgium", 13000, 9640));
            sales.Add(new SalesData(3, 0, "Denmark", 21000, 18100));
            sales.Add(new SalesData(4, 0, "Finland", 17000, 17420));
            sales.Add(new SalesData(5, 0, "France", 23020, 27000));
            sales.Add(new SalesData(6, 0, "Germany", 30540, 33000));
            sales.Add(new SalesData(7, 0, "Greece", 15600, 13200));
            sales.Add(new SalesData(8, 0, "Ireland", 9530, 10939));
            sales.Add(new SalesData(9, 0, "Italy", 17299, 19321));
            sales.Add(new SalesData(11, 0, "Netherlands", 8902, 9214));
            sales.Add(new SalesData(12, 0, "Norway", 5400, 7310));
            sales.Add(new SalesData(13, 0, "Portugal", 9220, 4271));
            sales.Add(new SalesData(14, 0, "Spain", 12900, 10300));
            sales.Add(new SalesData(15, 0, "Switzerland", 9323, 10730));
            sales.Add(new SalesData(16, 0, "United Kingdom", 14580, 13967));

            sales.Add(new SalesData(17, -1, "Eastern Europe", 22500, 24580));
            sales.Add(new SalesData(18, 17, "Belarus", 7315, 18800));
            sales.Add(new SalesData(19, 17, "Bulgaria", 6300, 2821));
            sales.Add(new SalesData(20, 17, "Croatia", 4200, 3890));
            sales.Add(new SalesData(21, 17, "Czech Republic", 19500, 15340));
            sales.Add(new SalesData(22, 17, "Hungary", 13495, 13900));
            sales.Add(new SalesData(23, 17, "Poland", 8930, 9440));
            sales.Add(new SalesData(24, 17, "Romania", 4900, 5100));
            sales.Add(new SalesData(25, 17, "Russia", 22500, 24580));

            sales.Add(new SalesData(26, -1, "North America", 31400, 32800));
            sales.Add(new SalesData(27, 26, "USA", 31400, 32800));
            sales.Add(new SalesData(28, 26, "Canada", 25390, 27000));

            sales.Add(new SalesData(29, -1, "South America", 16380, 15590));
            sales.Add(new SalesData(30, 29, "Argentina", 16380, 15590));
            sales.Add(new SalesData(31, 29, "Brazil", 4560, 5480));

            sales.Add(new SalesData(32, -1, "Asia", 20388, 22547));
            sales.Add(new SalesData(34, 32, "India", 4642, 5320));
            sales.Add(new SalesData(35, 32, "Japan", 9457, 12859));
            sales.Add(new SalesData(36, 32, "China", 20388, 22547));
            return sales;
        }
    }

}
vb
Imports System
Imports System.Collections.Generic
Imports System.ComponentModel
Imports System.Data
Imports System.Drawing
Imports System.Linq
Imports System.Text
Imports System.Windows.Forms
Imports DevExpress.XtraEditors
Imports DevExpress.Skins
Imports DevExpress.LookAndFeel
Imports DevExpress.UserSkins
Imports DevExpress.XtraTreeList.Columns

Namespace TreeList_UnboundDataViaEvent
    Partial Public Class Form1
        Inherits XtraForm

        Public Sub New()
            InitializeComponent()
            InitTreeList()
        End Sub

        Private Sub InitTreeList()
            treeList1.DataSource = SalesDataGenerator.CreateData()

            ' Create and customize an unbound column.
            Dim unbColumnMarchChange As New TreeListColumn()
            unbColumnMarchChange.UnboundDataType = GetType(Decimal)
            unbColumnMarchChange.Visible = True
            unbColumnMarchChange.OptionsColumn.AllowEdit = False
            unbColumnMarchChange.FieldName = "ChangeFromPrevYear"
            unbColumnMarchChange.Caption = "Change from Previous Year"
            unbColumnMarchChange.Format.FormatType = DevExpress.Utils.FormatType.Numeric
            unbColumnMarchChange.Format.FormatString = "p2"
            tlBandThisYear.Columns.Add(unbColumnMarchChange)
            ' Change the appearance settings after the column is added to the TreeList.
            unbColumnMarchChange.AppearanceHeader.Font = New Font(unbColumnMarchChange.AppearanceHeader.Font, FontStyle.Bold)
            unbColumnMarchChange.AppearanceCell.BackColor = Color.LightYellow
            ' Subcribe to the event that provides data for unbound columns.
            AddHandler treeList1.CustomUnboundColumnData, AddressOf TreeList1_CustomUnboundColumnData
            ' Resize columns proportionally.
            treeList1.ForceInitialize()
            treeList1.BestFitColumns()
        End Sub

        Private Sub TreeList1_CustomUnboundColumnData(ByVal sender As Object, ByVal e As DevExpress.XtraTreeList.TreeListCustomColumnDataEventArgs)
            If e.IsGetData AndAlso e.Column.FieldName = "ChangeFromPrevYear" Then
                Dim currentRow As SalesData = TryCast(e.Row, SalesData)
                If currentRow Is Nothing Then
                    Return
                End If
                e.Value = (currentRow.MarchSales - currentRow.MarchSalesPrev) / currentRow.MarchSalesPrev
            End If
        End Sub
    End Class

    Public Class SalesData
        Public Sub New(ByVal id As Integer, ByVal regionId As Integer, ByVal region As String, ByVal marchSales As Decimal, ByVal marchSalesPrev As Decimal)
            Me.ID = id
            Me.RegionID = regionId
            Me.Region = region
            Me.MarchSales = marchSales
            Me.MarchSalesPrev = marchSalesPrev
        End Sub
        Public Property ID() As Integer
        Public Property RegionID() As Integer
        Public Property Region() As String
        Public Property MarchSales() As Decimal
        Public Property MarchSalesPrev() As Decimal

    End Class
    Public Class SalesDataGenerator
        Public Shared Function CreateData() As List(Of SalesData)
            Dim sales As New List(Of SalesData)()
            sales.Add(New SalesData(0, -1, "Western Europe", 30540, 33000))
            sales.Add(New SalesData(1, 0, "Austria", 22000, 20000))
            sales.Add(New SalesData(2, 0, "Belgium", 13000, 9640))
            sales.Add(New SalesData(3, 0, "Denmark", 21000, 18100))
            sales.Add(New SalesData(4, 0, "Finland", 17000, 17420))
            sales.Add(New SalesData(5, 0, "France", 23020, 27000))
            sales.Add(New SalesData(6, 0, "Germany", 30540, 33000))
            sales.Add(New SalesData(7, 0, "Greece", 15600, 13200))
            sales.Add(New SalesData(8, 0, "Ireland", 9530, 10939))
            sales.Add(New SalesData(9, 0, "Italy", 17299, 19321))
            sales.Add(New SalesData(11, 0, "Netherlands", 8902, 9214))
            sales.Add(New SalesData(12, 0, "Norway", 5400, 7310))
            sales.Add(New SalesData(13, 0, "Portugal", 9220, 4271))
            sales.Add(New SalesData(14, 0, "Spain", 12900, 10300))
            sales.Add(New SalesData(15, 0, "Switzerland", 9323, 10730))
            sales.Add(New SalesData(16, 0, "United Kingdom", 14580, 13967))

            sales.Add(New SalesData(17, -1, "Eastern Europe", 22500, 24580))
            sales.Add(New SalesData(18, 17, "Belarus", 7315, 18800))
            sales.Add(New SalesData(19, 17, "Bulgaria", 6300, 2821))
            sales.Add(New SalesData(20, 17, "Croatia", 4200, 3890))
            sales.Add(New SalesData(21, 17, "Czech Republic", 19500, 15340))
            sales.Add(New SalesData(22, 17, "Hungary", 13495, 13900))
            sales.Add(New SalesData(23, 17, "Poland", 8930, 9440))
            sales.Add(New SalesData(24, 17, "Romania", 4900, 5100))
            sales.Add(New SalesData(25, 17, "Russia", 22500, 24580))

            sales.Add(New SalesData(26, -1, "North America", 31400, 32800))
            sales.Add(New SalesData(27, 26, "USA", 31400, 32800))
            sales.Add(New SalesData(28, 26, "Canada", 25390, 27000))

            sales.Add(New SalesData(29, -1, "South America", 16380, 15590))
            sales.Add(New SalesData(30, 29, "Argentina", 16380, 15590))
            sales.Add(New SalesData(31, 29, "Brazil", 4560, 5480))

            sales.Add(New SalesData(32, -1, "Asia", 20388, 22547))
            sales.Add(New SalesData(34, 32, "India", 4642, 5320))
            sales.Add(New SalesData(35, 32, "Japan", 9457, 12859))
            sales.Add(New SalesData(36, 32, "China", 20388, 22547))
            Return sales
        End Function
    End Class

End Namespace