Skip to main content

Grid Item - Fixed (Pinned) Columns

  • 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.

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;
}

Create a Control to Select Columns

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

public class CheckedComboBoxItem {
    public GridColumnBase Column { get; set; }
    public bool Checked { get; set; }
    public override string ToString() {
        return Column.GetDisplayName();
    }
}

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.

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;
}

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

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;
}

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.

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);
                }
        }
    }
}

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.

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;
                }
            }
        }
    }
}

Register the Custom Functionality Module

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

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;
        }
    }
}

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.

using WindowsFormsAppCustomProperties;
//...
public Form1() {
    InitializeComponent();
    new GridFixedColumnModule(dashboardDesigner1, svgImageCollection1["alignverticalleft"]);
    dashboardDesigner1.LoadDashboard("../../Dashboard/newDashboard.xml");
//...
}

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