Back to Devexpress

Grid Item - Fixed (Pinned) Columns

dashboard-401622-winforms-dashboard-winforms-designer-ui-elements-and-customization-create-custom-properties-grid-item-fixed-pinned-columns.md

latest25.0 KB
Original Source

Grid Item - Fixed (Pinned) Columns

  • Oct 15, 2021
  • 10 minutes to read

This topic describes how to create a custom property for a data item container. In this example, the custom property pins a column to the Grid item in the WinForms Dashboard Designer.

View Example: WinForms Dashboard - Custom Properties

Create the Custom Functionality Module

The code is organized into a separate module you can integrate in any dashboard application.

Create the GridFixedColumnModule class that serves as a custom functionality module and contains:

  • a dashboard control that you pass as a parameter when you register the module,
  • a custom property’s unique name,
  • event subscriptions that are used to provide custom functionality,
  • a ribbon in which you add a button to edit custom property’s value.

Note

You can use the IDashboardControl interface that provides common API for WinForms Designer and Viewer to write code that can be used in both controls simultaneously.

You can add control elements to the Ribbon / Toolbar to change the custom property’s value in the UI.

In this example, the Fix Columns button is in the Custom Properties group on the Grid’s Design page.

csharp
public class GridFixedColumnModule {
public static readonly string PropertyName = "FixedColumns";
readonly DashboardDesigner designer;
public GridFixedColumnModule(DashboardDesigner designer, SvgImage barImage = null) {
    this.designer = designer;
    RibbonControl ribbon = (RibbonControl)designer.MenuManager;
    RibbonPage page = ribbon.GetDashboardRibbonPage(DashboardBarItemCategory.GridTools, DashboardRibbonPage.Design);
    RibbonPageGroup group = page.GetGroupByName("Custom Properties");
    if(group == null) {
        group = new RibbonPageGroup("Custom Properties") { Name = "Custom Properties" };
        page.Groups.Add(group);
    }
    BarButtonItem barItem = CreateBarItem("Fix Columns", barImage);
    group.ItemLinks.Add(barItem);
    barItem.ItemClick += ChangeCustomPropertyValue;
    designer.DashboardItemControlUpdated += Designer_DashboardItemControlUpdated;
}
vb
Public Class GridFixedColumnModule
Public Shared ReadOnly PropertyName As String = "FixedColumns"
Private ReadOnly designer As DashboardDesigner
Public Sub New(ByVal designer As DashboardDesigner, Optional ByVal barImage As SvgImage = Nothing)
    Me.designer = designer
    Dim ribbon As RibbonControl = CType(designer.MenuManager, RibbonControl)
    Dim page As RibbonPage = ribbon.GetDashboardRibbonPage(DashboardBarItemCategory.GridTools, DashboardRibbonPage.Design)
    Dim group As RibbonPageGroup = page.GetGroupByName("Custom Properties")
    If group Is Nothing Then
        group = New RibbonPageGroup("Custom Properties") With {.Name = "Custom Properties"}
        page.Groups.Add(group)
    End If
    Dim barItem As BarButtonItem = CreateBarItem("Fix Columns", barImage)
    group.ItemLinks.Add(barItem)
    barItem.ItemClick += ChangeCustomPropertyValue
    designer.DashboardItemControlUpdated += Designer_DashboardItemControlUpdated
End Sub
csharp
BarButtonItem CreateBarItem(string caption, SvgImage barImage) {
    BarButtonItem barItem = new BarButtonItem();
    barItem.Caption = caption;
    barItem.ImageOptions.SvgImage = barImage;
    return barItem;
}
vb
Private Function CreateBarItem(ByVal caption As String, ByVal barImage As SvgImage) As BarButtonItem
    Dim barItem As New BarButtonItem()
    barItem.Caption = caption
    barItem.ImageOptions.SvgImage = barImage
    Return barItem
End Function

Create a Control to Select Columns

Create the CheckedComboBoxItem class that returns a list of grid columns and their checked state.

csharp
public class CheckedComboBoxItem {
    public GridColumnBase Column { get; set; }
    public bool Checked { get; set; }
    public override string ToString() {
        return Column.GetDisplayName();
    }
}
vb
Public Class CheckedComboBoxItem
    Public Property Column() As GridColumnBase
    Public Property Checked() As Boolean

    Public Overrides Function ToString() As String
        Return Column.GetDisplayName()
    End Function
End Class

Create the XtraUserControl class instance and pass a list of CheckedComboBoxItem objects to its constructor. Subscribe to the BaseCheckedListBoxControl.ItemCheck event to check the columns checked status and specify whether they should be pinned.

csharp
public class ColumnSelectorControl: XtraUserControl {
CheckedListBoxControl checkedCombo = new CheckedListBoxControl();
public ColumnSelectorControl(List<CheckedComboBoxItem> gridColumns) {
    foreach(CheckedComboBoxItem col in gridColumns) {
        checkedCombo.Items.Add(col, col.Checked);
    }
    checkedCombo.ItemCheck += CheckedCombo_ItemCheck;
    checkedCombo.Dock = DockStyle.Fill;
    Controls.Add(checkedCombo);
    Dock = DockStyle.Top;
}
vb
Public Class ColumnSelectorControl
    Inherits XtraUserControl
Private checkedCombo As New CheckedListBoxControl()
Public Sub New(ByVal gridColumns As List(Of CheckedComboBoxItem))
    For Each col As CheckedComboBoxItem In gridColumns
        checkedCombo.Items.Add(col, col.Checked)
    Next col
    checkedCombo.ItemCheck += CheckedCombo_ItemCheck
    checkedCombo.Dock = DockStyle.Fill
    Controls.Add(checkedCombo)
    Dock = DockStyle.Top
End Sub

The ItemCheck event is raised each time your select the column in the ComboBox.

csharp
void CheckedCombo_ItemCheck(object sender, DevExpress.XtraEditors.Controls.ItemCheckEventArgs e) {
    CheckedListBoxControl checkList = sender as CheckedListBoxControl;
    CheckedComboBoxItem item = checkList.Items[e.Index].Value as CheckedComboBoxItem;
    item.Checked = checkList.Items[e.Index].CheckState == CheckState.Checked;
}
vb
Private Sub CheckedCombo_ItemCheck(ByVal sender As Object, ByVal e As DevExpress.XtraEditors.Controls.ItemCheckEventArgs)
    Dim checkList As CheckedListBoxControl = TryCast(sender, CheckedListBoxControl)
    Dim item As CheckedComboBoxItem = TryCast(checkList.Items(e.Index).Value, CheckedComboBoxItem)
    item.Checked = checkList.Items(e.Index).CheckState = CheckState.Checked
End Sub

Save the Custom Property’s Value to a Dashboard

In this example, the custom property’s value is stored in the DataItemContainer.CustomProperties collection.

Use the DashboardDesigner.AddToHistory method to record a new custom property’s value and save the action to the Dashboard Designer’s history when a user changes the value. This method calls the CustomProperties.SetValue method and adds the information to the history item. You can undo/redo this action like other user actions.

csharp
void ChangeCustomPropertyValue(object sender, ItemClickEventArgs e) {
        GridDashboardItem gridItem = designer.SelectedDashboardItem as GridDashboardItem;
        List<CheckedComboBoxItem> checkedColumnsList = gridItem.Columns.Select(x => new CheckedComboBoxItem() { 
            Column = x, 
            Checked = Convert.ToBoolean(x.CustomProperties.GetValue(PropertyName)) 
        }).ToList();
        ColumnSelectorControl control = new ColumnSelectorControl(checkedColumnsList);
        if(XtraDialog.Show(control, "Select columns to fix:") == DialogResult.OK) {
            foreach(var item in checkedColumnsList)
                if(Convert.ToBoolean(item.Column.CustomProperties.GetValue(PropertyName)) != item.Checked) {
                    string status = item.Checked == true ? "Pin" : "Unpin";
                    CustomPropertyHistoryItem historyItem = new CustomPropertyHistoryItem(item.Column, PropertyName, item.Checked.ToString(), $"{status} the {item} column");
                    designer.AddToHistory(historyItem);
                }
        }
    }
}
vb
Private Sub ChangeCustomPropertyValue(ByVal sender As Object, ByVal e As ItemClickEventArgs)
    Dim gridItem As GridDashboardItem = TryCast(designer.SelectedDashboardItem, GridDashboardItem)
    Dim checkedColumnsList As List(Of CheckedComboBoxItem) = gridItem.Columns.Select(Function(x) New CheckedComboBoxItem() With {
        .Column = x,
        .Checked = Convert.ToBoolean(x.CustomProperties.GetValue(PropertyName))
    }).ToList()
    Dim control As New ColumnSelectorControl(checkedColumnsList)
    If XtraDialog.Show(control, "Select columns to fix:") = DialogResult.OK Then
        For Each item In checkedColumnsList
            If Convert.ToBoolean(item.Column.CustomProperties.GetValue(PropertyName)) <> item.Checked Then
                Dim status As String = If(item.Checked = True, "Pin", "Unpin")
                Dim historyItem As New CustomPropertyHistoryItem(item.Column, PropertyName, item.Checked.ToString(), $"{status} the {item} column")
                designer.AddToHistory(historyItem)
            End If
        Next item
    End If
End Sub

Apply the Custom Property’s Value to the Underlying Control

Handle the DashboardItemControlUpdated event to access the underlying Grid control and enable fixed columns. Use the CustomProperties.GetValue method to obtain the custom property’s value and update the selected column according to the value.

csharp
void Designer_DashboardItemControlUpdated(object sender, DashboardItemControlEventArgs e) {
    if(e.GridControl != null) {
        GridDashboardItem gridItem = designer.Dashboard.Items[e.DashboardItemName] as GridDashboardItem;
        gridItem.GridOptions.ColumnWidthMode = GridColumnWidthMode.AutoFitToContents;
        foreach(GridColumnBase itemColumn in gridItem.Columns) {
            string customProperty = itemColumn.CustomProperties.GetValue(PropertyName);
            if(!string.IsNullOrEmpty(customProperty)) {
                GridColumn gridColumn = e.GridContext.GetControlColumn(itemColumn);
                if(gridColumn != null) {
                    bool fixedWidthEnabled = Convert.ToBoolean(itemColumn.CustomProperties.GetValue(PropertyName));
                    gridColumn.Fixed = fixedWidthEnabled ? FixedStyle.Left : FixedStyle.None;
                }
            }
        }
    }
}
vb
Private Sub Designer_DashboardItemControlUpdated(ByVal sender As Object, ByVal e As DashboardItemControlEventArgs)
    If e.GridControl IsNot Nothing Then
        Dim gridItem As GridDashboardItem = TryCast(designer.Dashboard.Items(e.DashboardItemName), GridDashboardItem)
        gridItem.GridOptions.ColumnWidthMode = GridColumnWidthMode.AutoFitToContents
        For Each itemColumn As GridColumnBase In gridItem.Columns
            Dim customProperty As String = itemColumn.CustomProperties.GetValue(PropertyName)
            If Not String.IsNullOrEmpty(customProperty) Then
                Dim gridColumn As GridColumn = e.GridContext.GetControlColumn(itemColumn)
                If gridColumn IsNot Nothing Then
                    Dim fixedWidthEnabled As Boolean = Convert.ToBoolean(itemColumn.CustomProperties.GetValue(PropertyName))
                    gridColumn.Fixed = If(fixedWidthEnabled, FixedStyle.Left, FixedStyle.None)
                End If
            End If
        Next itemColumn
    End If
 End Sub

Register the Custom Functionality Module

The code below is a complete module you need to add the Grid item’s Fix Columns option:

csharp
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using DevExpress.DashboardCommon;
using DevExpress.DashboardWin;
using DevExpress.Utils.Svg;
using DevExpress.XtraBars;
using DevExpress.XtraBars.Ribbon;
using DevExpress.XtraEditors;
using DevExpress.XtraGrid.Columns;

namespace WindowsFormsAppCustomProperties {
    public class GridFixedColumnModule {
        public static readonly string PropertyName = "FixedColumns";
        readonly DashboardDesigner designer;

        public GridFixedColumnModule(DashboardDesigner designer, SvgImage barImage = null) {
            this.designer = designer;
            RibbonControl ribbon = (RibbonControl)designer.MenuManager;
            RibbonPage page = ribbon.GetDashboardRibbonPage(DashboardBarItemCategory.GridTools, DashboardRibbonPage.Design);
            RibbonPageGroup group = page.GetGroupByName("Custom Properties");
            if(group == null) {
                group = new RibbonPageGroup("Custom Properties") { Name = "Custom Properties" };
                page.Groups.Add(group);
            }
            BarButtonItem barItem = CreateBarItem("Fix Columns", barImage);
            group.ItemLinks.Add(barItem);
            barItem.ItemClick += ChangeCustomPropertyValue;
            designer.DashboardItemControlUpdated += Designer_DashboardItemControlUpdated;
        }
        BarButtonItem CreateBarItem(string caption, SvgImage barImage) {
            BarButtonItem barItem = new BarButtonItem();
            barItem.Caption = caption;
            barItem.ImageOptions.SvgImage = barImage;
            return barItem;
        }
        void Designer_DashboardItemControlUpdated(object sender, DashboardItemControlEventArgs e) {
            if(e.GridControl != null) {
                GridDashboardItem gridItem = designer.Dashboard.Items[e.DashboardItemName] as GridDashboardItem;
                gridItem.GridOptions.ColumnWidthMode = GridColumnWidthMode.AutoFitToContents;
                foreach(GridColumnBase itemColumn in gridItem.Columns) {
                    string customProperty = itemColumn.CustomProperties.GetValue(PropertyName);
                    if(!string.IsNullOrEmpty(customProperty)) {
                        GridColumn gridColumn = e.GridContext.GetControlColumn(itemColumn);
                        if(gridColumn != null) {
                            bool fixedWidthEnabled = Convert.ToBoolean(itemColumn.CustomProperties.GetValue(PropertyName));
                            gridColumn.Fixed = fixedWidthEnabled ? FixedStyle.Left : FixedStyle.None;
                        }
                    }
                }
            }
        }
    void ChangeCustomPropertyValue(object sender, ItemClickEventArgs e) {
            GridDashboardItem gridItem = designer.SelectedDashboardItem as GridDashboardItem;
            List<CheckedComboBoxItem> checkedColumnsList = gridItem.Columns.Select(x => new CheckedComboBoxItem() { 
                Column = x, 
                Checked = Convert.ToBoolean(x.CustomProperties.GetValue(PropertyName)) 
            }).ToList();
            ColumnSelectorControl control = new ColumnSelectorControl(checkedColumnsList);
            if(XtraDialog.Show(control, "Select columns to fix:") == DialogResult.OK) {
                foreach(var item in checkedColumnsList)
                    if(Convert.ToBoolean(item.Column.CustomProperties.GetValue(PropertyName)) != item.Checked) {
                        string status = item.Checked == true ? "Pin" : "Unpin";
                        CustomPropertyHistoryItem historyItem = new CustomPropertyHistoryItem(item.Column, PropertyName, item.Checked.ToString(), $"{status} the {item} column");
                        designer.AddToHistory(historyItem);
                    }
            }
        }
    }

    public class CheckedComboBoxItem {
        public GridColumnBase Column { get; set; }
        public bool Checked { get; set; }
        public override string ToString() {
            return Column.GetDisplayName();
        }
    }
    public class ColumnSelectorControl: XtraUserControl {
        CheckedListBoxControl checkedCombo = new CheckedListBoxControl();
        public ColumnSelectorControl(List<CheckedComboBoxItem> gridColumns) {
            foreach(CheckedComboBoxItem col in gridColumns) {
                checkedCombo.Items.Add(col, col.Checked);
            }
            checkedCombo.ItemCheck += CheckedCombo_ItemCheck;
            checkedCombo.Dock = DockStyle.Fill;
            Controls.Add(checkedCombo);
            Dock = DockStyle.Top;
        }

        void CheckedCombo_ItemCheck(object sender, DevExpress.XtraEditors.Controls.ItemCheckEventArgs e) {
            CheckedListBoxControl checkList = sender as CheckedListBoxControl;
            CheckedComboBoxItem item = checkList.Items[e.Index].Value as CheckedComboBoxItem;
            item.Checked = checkList.Items[e.Index].CheckState == CheckState.Checked;
        }
    }
}
vb
Imports System
Imports System.Collections.Generic
Imports System.Linq
Imports System.Windows.Forms
Imports DevExpress.DashboardCommon
Imports DevExpress.DashboardWin
Imports DevExpress.Utils.Svg
Imports DevExpress.XtraBars
Imports DevExpress.XtraBars.Ribbon
Imports DevExpress.XtraEditors
Imports DevExpress.XtraGrid.Columns

Namespace WindowsFormsAppCustomProperties
    Public Class GridFixedColumnModule
        Public Shared ReadOnly PropertyName As String = "FixedColumns"
        Private ReadOnly designer As DashboardDesigner

        Public Sub New(ByVal designer As DashboardDesigner, Optional ByVal barImage As SvgImage = Nothing)
            Me.designer = designer
            Dim ribbon As RibbonControl = CType(designer.MenuManager, RibbonControl)
            Dim page As RibbonPage = ribbon.GetDashboardRibbonPage(DashboardBarItemCategory.GridTools, DashboardRibbonPage.Design)
            Dim group As RibbonPageGroup = page.GetGroupByName("Custom Properties")
            If group Is Nothing Then
                group = New RibbonPageGroup("Custom Properties") With {.Name = "Custom Properties"}
                page.Groups.Add(group)
            End If
            Dim barItem As BarButtonItem = CreateBarItem("Fix Columns", barImage)
            group.ItemLinks.Add(barItem)
            AddHandler barItem.ItemClick, AddressOf ChangeCustomPropertyValue
            AddHandler designer.DashboardItemControlUpdated, AddressOf Designer_DashboardItemControlUpdated
        End Sub
        Private Function CreateBarItem(ByVal caption As String, ByVal barImage As SvgImage) As BarButtonItem
            Dim barItem As New BarButtonItem()
            barItem.Caption = caption
            barItem.ImageOptions.SvgImage = barImage
            Return barItem
        End Function
        Private Sub Designer_DashboardItemControlUpdated(ByVal sender As Object, ByVal e As DashboardItemControlEventArgs)
            If e.GridControl IsNot Nothing Then
                Dim gridItem As GridDashboardItem = TryCast(designer.Dashboard.Items(e.DashboardItemName), GridDashboardItem)
                gridItem.GridOptions.ColumnWidthMode = GridColumnWidthMode.AutoFitToContents
                For Each itemColumn As GridColumnBase In gridItem.Columns
                    Dim customProperty As String = itemColumn.CustomProperties.GetValue(PropertyName)
                    If Not String.IsNullOrEmpty(customProperty) Then
                        Dim gridColumn As GridColumn = e.GridContext.GetControlColumn(itemColumn)
                        If gridColumn IsNot Nothing Then
                            Dim fixedWidthEnabled As Boolean = Convert.ToBoolean(itemColumn.CustomProperties.GetValue(PropertyName))
                            gridColumn.Fixed = If(fixedWidthEnabled, FixedStyle.Left, FixedStyle.None)
                        End If
                    End If
                Next itemColumn
            End If
        End Sub
    Private Sub ChangeCustomPropertyValue(ByVal sender As Object, ByVal e As ItemClickEventArgs)
            Dim gridItem As GridDashboardItem = TryCast(designer.SelectedDashboardItem, GridDashboardItem)
            Dim checkedColumnsList As List(Of CheckedComboBoxItem) = gridItem.Columns.Select(Function(x) New CheckedComboBoxItem() With {
                .Column = x,
                .Checked = Convert.ToBoolean(x.CustomProperties.GetValue(PropertyName))
            }).ToList()
            Dim control As New ColumnSelectorControl(checkedColumnsList)
            If XtraDialog.Show(control, "Select columns to fix:") = DialogResult.OK Then
                For Each item In checkedColumnsList
                    If Convert.ToBoolean(item.Column.CustomProperties.GetValue(PropertyName)) <> item.Checked Then
                        Dim status As String = If(item.Checked = True, "Pin", "Unpin")
                        Dim historyItem As New CustomPropertyHistoryItem(item.Column, PropertyName, item.Checked.ToString(), $"{status} the {item} column")
                        designer.AddToHistory(historyItem)
                    End If
                Next item
            End If
        End Sub
    End Class
    Public Class CheckedComboBoxItem
        Public Property Column() As GridColumnBase
        Public Property Checked() As Boolean

        Public Overrides Function ToString() As String
            Return Column.GetDisplayName()
        End Function
    End Class
    Public Class ColumnSelectorControl
        Inherits XtraUserControl
        Private checkedCombo As New CheckedListBoxControl()
        Public Sub New(ByVal gridColumns As List(Of CheckedComboBoxItem))
            For Each col As CheckedComboBoxItem In gridColumns
                checkedCombo.Items.Add(col, col.Checked)
            Next col
            AddHandler checkedCombo.ItemCheck, AddressOf CheckedCombo_ItemCheck
            checkedCombo.Dock = DockStyle.Fill
            Controls.Add(checkedCombo)
            Dock = DockStyle.Top
        End Sub

        Private Sub CheckedCombo_ItemCheck(ByVal sender As Object, ByVal e As DevExpress.XtraEditors.Controls.ItemCheckEventArgs)
            Dim checkList As CheckedListBoxControl = TryCast(sender, CheckedListBoxControl)
            Dim item As CheckedComboBoxItem = TryCast(checkList.Items(e.Index).Value, CheckedComboBoxItem)
            item.Checked = checkList.Items(e.Index).CheckState = CheckState.Checked
        End Sub
    End Class
End Namespace

Register the created module before you load a dashboard to apply custom settings to this dashboard. For this, create a new GridFixedColumnModule instance and pass the Dashboard Designer for which you register a custom property. You can create the SvgImageCollection instance to store vector images and use one of them as an icon for the bar item.

csharp
using WindowsFormsAppCustomProperties;
//...
public Form1() {
    InitializeComponent();
    new GridFixedColumnModule(dashboardDesigner1, svgImageCollection1["alignverticalleft"]);
    dashboardDesigner1.LoadDashboard("../../Dashboard/newDashboard.xml");
//...
}
vb
Imports WindowsFormsAppCustomProperties
'...
Public Sub New()
    InitializeComponent()
    Dim TempGridFixedColumnModule As GridFixedColumnModule = New GridFixedColumnModule(dashboardDesigner1, svgImageCollection1("alignverticalleft"))
    dashboardDesigner1.LoadDashboard("../../Dashboard/newDashboard.xml")
'...
End Sub

Result

After you registered the GridFixedColumnModule module, the FixedColumn button is added that invokes the pop-up comboBox menu that contains the selected grid item’s data fields. Select the fields you want to pin and click OK.

you can undo/redo actions because information about the scale break property’s state is saved in history.

See Also

Create Custom Properties