windowsforms-17831-controls-and-libraries-tree-list-feature-center-data-binding-unbound-columns.md
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.
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.
TreeListColumn unboundCol1 = new TreeListColumn();
unboundCol1.UnboundDataType = typeof(int);
unboundCol1.FieldName = "MyUnboundColumn1";
treeList1.Columns.Add(unboundCol1);
unboundCol1.Visible = true;
Dim unboundCol1 As TreeListColumn = New TreeListColumn()
unboundCol1.UnboundDataType = GetType(Int32)
unboundCol1.FieldName = "MyUnboundColumn1"
TreeList1.Columns.Add(unboundCol1)
unboundCol1.Visible = true
Provide data for unbound columns using one of two approaches:
Set a formula (string expression) to the TreeListColumn.UnboundExpression property. In expressions, you can refer to other columns, and use various functions and operators.
Handle the TreeList.CustomUnboundColumnData event. This event can also be used to save any changes made by an end-user in unbound columns.
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:
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.
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.
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();
}
}
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
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.
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;
}
}
}
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