Create an Interactive Data-Aware Item for the WinForms Dashboard
- 13 minutes to read
This tutorial shows you how to embed additional functionality, such as export, coloring, and interactivity in a custom item. In the previous tutorial you bound a custom item to data. In this tutorial, you will enable master filtering and drill-down interactivity, coloring, and export in the Funnel custom item.
First, create a WinForms Dashboard project and create the CustomItems folder in it to store custom item data. Then, follow the instructions below:
Create Metadata
Metadata is a CustomItemMetadata descendant that describes options and settings available to a user in the UI. Register the metadata object to be able to create custom items of this type. The structure you specified in metadata defines these custom items in a dashboard definition.
Add a new class called FunnelItemMetadata.cs to the CustomItems folder in your project. In the file, derive a class from CustomItemMetadata
and declare its properties that correspond to data sections in the binding panel. The Value
property allows you to add an individual data item to the section. The Arguments
collection property allows you to add several data items.
Apply the following class attributes to FunnelItemMetadata
:
Name | Description |
---|---|
DisplayNameAttribute | Specifies a name for a custom item’s icon. |
CustomItemDescriptionAttribute | Specifies tooltip text that is displayed for a custom item’s bar in the Ribbon. |
CustomItemImageAttribute | Specifies an icon for a custom item’s bar in the Ribbon. |
Add an SVG file you want to use as a custom item’s icon to the Images folder in your project. You can use SVG images from the example: WinForms Dashboard - Custom Items. Make sure an SVG file’s Build Action property is set to Embedded Resource.
Apply the following attributes to FunnelItemMetadata’s properties:
Name | Description |
---|---|
DisplayNameAttribute | Specifies a data section’s name in the Data Items pane. |
EmptyDataItemPlaceholderAttribute | Specifies placeholder text for a pane where you can place a data item. |
SupportColoringAttribute | Specifies whether data items in a section support coloring. |
SupportInteractivityAttribute | Specifies whether data items in a data section support interactivity. |
using System.ComponentModel;
using DevExpress.DashboardCommon;
namespace TutorialsCustomItems {
[DisplayName("Funnel"),
CustomItemDescription("Funnel description"),
CustomItemImage("TutorialsCustomItems.Images.Funnel.svg")]
public class FunnelItemMetadata : CustomItemMetadata {
[DisplayName("Value"),
EmptyDataItemPlaceholder("Value"),
SupportColoring(DefaultColoringMode.None)]
public Measure Value {
get { return GetPropertyValue<Measure>(); }
set { SetPropertyValue(value); }
}
[DisplayName("Arguments"),
EmptyDataItemPlaceholder("My Argument"),
SupportColoring(DefaultColoringMode.Hue),
SupportInteractivity]
public DimensionCollection Arguments { get; } = new DimensionCollection();
}
}
Register a New Metadata Type
Call the CustomItemMetadataTypes.Register<T>() method before the main application form is created to allow the Dashboard Designer to read custom item data from a dashboard. Pass a new metadata type to the method. The metadata type is stored in the CustomItemMetadataTypes collection corresponds to the FunnelItemMetadata
class.
using DevExpress.XtraEditors;
using System;
using System.Windows.Forms;
using DevExpress.DashboardCommon;
using TutorialsCustomItems.CustomItems;
namespace TutorialsCustomItems {
static class Program{
/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main(){
// ...
Dashboard.CustomItemMetadataTypes.Register<FunnelItemMetadata>();
Application.Run(new Form1());
}
}
}
The Dashboard Designer automatically creates a binding panel based on metadata for the custom item.
Add a Button to the Ribbon
Call the DashboardDesigner.CreateCustomItemBars(Type[]) method to insert a custom item’s bar in the Ribbon. Click the bar to create a custom item in the Dashboard Designer at runtime.
using System.Windows.Forms;
using DevExpress.DashboardCommon;
using DevExpress.DashboardWin;
namespace TutorialsCustomItems {
public partial class Form1 : Form {
public Form1(){
InitializeComponent();
dashboardDesigner1.CreateRibbon();
dashboardDesigner1.CreateCustomItemBars();
}
}
}
Create and Configure a Custom Control
A custom control displays a custom item in a dashboard. To configure the custom control, add the FunnelItemControlProvider.cs file to the CustomItems folder. In the file, derive the FunnelItemControlProvider
class from CustomControlProviderBase
. FunnelItemControlProvider
creates and updates the control based on data that a dashboard transfers to the object.
The CustomControlProviderBase.Control property gets the control that displays the custom item.
Event subscriptions are used for further customization.
using System.Windows.Forms;
using DevExpress.DashboardCommon;
using DevExpress.DashboardWin;
using DevExpress.XtraCharts;
using DevExpress.XtraReports.UI;
using System.Linq;
namespace TutorialsCustomItems {
public class FunnelItemControlProvider : CustomControlProviderBase {
CustomDashboardItem<FunnelItemMetadata> dashboardItem;
ChartControl chart;
DashboardFlatDataSource flatData;
protected override Control Control { get { return chart; } }
public FunnelItemControlProvider(CustomDashboardItem<FunnelItemMetadata> dashboardItem) {
this.dashboardItem = dashboardItem;
chart = new ChartControl();
chart.RuntimeHitTesting = true;
chart.BorderOptions.Visibility = DevExpress.Utils.DefaultBoolean.False;
chart.SeriesSelectionMode = SeriesSelectionMode.Point;
chart.MouseDoubleClick += MouseDoubleClick;
chart.SelectedItemsChanged += ChartSelectedItemsChanged;
chart.SelectedItemsChanging += ChartSelectedItemsChanging;
chart.CustomDrawSeriesPoint += CustomDrawSeriesPoint;
}
// ...
}
}
Add Coloring
SupportColoringAttribute identifies that the Funnel item can use coloring. When you get DashboardFlatDataSource, you can include color values calculated for each data row. To accomplish this, set the DashboardFlatDataSourceOptions.AddColoringColumns to true and pass the DashboardFlatDataSourceOptions
object to the CustomItemData.GetFlatData(DashboardFlatDataSourceOptions) method. Then, you can use the DashboardFlatDataSource.GetColoringColumn(String) method to bind the column to Funnel chart series.
public class FunnelItemControlProvider : CustomControlProviderBase {
DashboardFlatDataSource flatData;
// ...
protected override void UpdateControl(CustomItemData customItemData){
// ...
flatData = customItemData.GetFlatData(new DashboardFlatDataSourceOptions() { AddColoringColumns = true });
Series series = ConfigureSeries(flatData);
chart.Series.Add(series);
}
Series ConfigureSeries(DashboardFlatDataSource flatData){
Series series = new Series("A Funnel Series", ViewType.Funnel);
if (dashboardItem.Metadata.Value != null && dashboardItem.Metadata.Arguments.Count > 0){
series.DataSource = flatData;
series.ValueDataMembers.AddRange(dashboardItem.Metadata.Value.UniqueId);
if (Interactivity.IsDrillDownEnabled){
int drillDownLevel = Interactivity.GetCurrentDrillDownValues().Count;
series.ArgumentDataMember = dashboardItem.Metadata.Arguments[drillDownLevel].UniqueId;
}
else
series.ArgumentDataMember = dashboardItem.Metadata.Arguments.Last().UniqueId;
series.ColorDataMember = flatData.GetColoringColumn(dashboardItem.Metadata.Value.UniqueId).Name;
}
((FunnelSeriesLabel)series.Label).Position = FunnelSeriesLabelPosition.Center;
FunnelSeriesView seriesView = series.View as FunnelSeriesView;
return series;
}
}
Configure Interactivity
SupportInteractivityAttribute identifies that you can make the Funnel item interactive. To do this, you need to configure master filtering and drill down in the FunnelItemControlProvider
class.
Master Filtering
Override the CustomControlProviderBase.SetSelection(CustomItemSelection) method to update a custom control according to the current master filter selection. The method is called each time a master filter selection changes.
protected override void SetSelection(CustomItemSelection selection){
chart.ClearSelection();
foreach (DashboardFlatDataSourceRow item in selection.GetDashboardFlatDataSourceRows(flatData))
chart.SelectedItems.Add(item);
}
In this tutorial, we use the CustomControlProviderBase.Interactivity property with its methods to set the master filter in a ChartSelectionChanged
event handler. The ChartSelectedItemsChanged
event occurs every time you click on the Funnel’s value in the UI. The ICustomItemInteractivityProvider.SetMasterFilter(Object) method sets a new selected value, and the SetSelection
method is called once the value is changed.
void ChartSelectedItemsChanged(object sender, SelectedItemsChangedEventArgs e){
if (chart.SelectedItems.Count == 0 && Interactivity.CanClearMasterFilter)
Interactivity.ClearMasterFilter();
else if (Interactivity.CanSetMasterFilter)
Interactivity.SetMasterFilter(chart.SelectedItems.OfType<DashboardFlatDataSourceRow>());
}
void ChartSelectedItemsChanging(object sender, SelectedItemsChangingEventArgs e){
if (Interactivity.MasterFilterMode == DashboardItemMasterFilterMode.Single && e.NewItems.OfType<DashboardFlatDataSourceRow>().Count() == 0)
e.Cancel = true;
}
The Clear Master Filter button also calls the SetSelection
method.
To update the ChartControl.SelectionMode property according to the actual master filter mode, use the following code:
void UpdateSelectionMode(){
switch (Interactivity.MasterFilterMode){
case DashboardItemMasterFilterMode.Single:
chart.SelectionMode = ElementSelectionMode.Single;
break;
case DashboardItemMasterFilterMode.Multiple:
chart.SelectionMode = ElementSelectionMode.Extended;
break;
default:
chart.SelectionMode = ElementSelectionMode.None;
break;
}
}
The master filter initial behavior depends on the selected mode.
Multiple
When you launch the application, this mode does not apply any selection when the custom item is initialized. Such behavior equals to neutral filter mode state.
Single
When you launch the application, this mode requires one selected value when the custom item is initialized. To select a value, add a DashboardFlatDataSourceRow object to the selected item collection in the
SetSelection
method. The method adds the first row in DashboardFlatDataSource.
Drill-Down
Call the ICustomItemInteractivityProvider.PerformDrillDown(Object) method in a MouseDoubleClick
event handler to execute drill down.
void MouseDoubleClick(object sender, MouseEventArgs e){
ChartHitInfo hitInfo = chart.CalcHitInfo(e.Location);
if (hitInfo.InSeriesPoint){
if (Interactivity.CanPerformDrillDown)
Interactivity.PerformDrillDown(hitInfo.SeriesPoint.Tag as DashboardFlatDataSourceRow);
}
}
The Dashboard Designer does not calculate data item values that do not fall into the current drill-down level.
The ICustomItemInteractivityProvider.GetCurrentDrillDownValues() method is used to determine the current drill-down level. A Dashboard displays the last data item in the Argument section, if drill-down is disabled.
Series ConfigureSeries(DashboardFlatDataSource flatData){
Series series = new Series("A Funnel Series", ViewType.Funnel);
if (dashboardItem.Metadata.Value != null && dashboardItem.Metadata.Arguments.Count > 0){
series.DataSource = flatData;
series.ValueDataMembers.AddRange(dashboardItem.Metadata.Value.UniqueId);
if (Interactivity.IsDrillDownEnabled){
int drillDownLevel = Interactivity.GetCurrentDrillDownValues().Count;
series.ArgumentDataMember = dashboardItem.Metadata.Arguments[drillDownLevel].UniqueId;
}
else
series.ArgumentDataMember = dashboardItem.Metadata.Arguments.Last().UniqueId;
series.ColorDataMember = flatData.GetColoringColumn(dashboardItem.Metadata.Value.UniqueId).Name;
}
((FunnelSeriesLabel)series.Label).Position = FunnelSeriesLabelPosition.Center;
return series;
}
Update a Custom Control
The CustomControlProviderBase.UpdateControl(CustomItemData) method is called each time the custom item’s data or settings change. The method supplies data for the custom item based on measures and dimensions that are specified in metadata. Call the CustomItemData.GetFlatData() method to get custom item data and bind it to the control.
The CustomDrawSeriesPoint event formats text values of labels and legend.
// ...
protected override void UpdateControl(CustomItemData customItemData){
UpdateSelectionMode();
flatData = customItemData.GetFlatData(new DashboardFlatDataSourceOptions() { AddColoringColumns = true });
chart.Series.Clear();
Series series = ConfigureSeries(flatData);
chart.Series.Add(series);
}
Series ConfigureSeries(DashboardFlatDataSource flatData){
Series series = new Series("A Funnel Series", ViewType.Funnel);
if (dashboardItem.Metadata.Value != null && dashboardItem.Metadata.Arguments.Count > 0){
series.DataSource = flatData;
series.ValueDataMembers.AddRange(dashboardItem.Metadata.Value.UniqueId);
if (Interactivity.IsDrillDownEnabled){
int drillDownLevel = Interactivity.GetCurrentDrillDownValues().Count;
series.ArgumentDataMember = dashboardItem.Metadata.Arguments[drillDownLevel].UniqueId;
}
else
series.ArgumentDataMember = dashboardItem.Metadata.Arguments.Last().UniqueId;
series.ColorDataMember = flatData.GetColoringColumn(dashboardItem.Metadata.Value.UniqueId).Name;
}
((FunnelSeriesLabel)series.Label).Position = FunnelSeriesLabelPosition.Center;
return series;
}
void CustomDrawSeriesPoint(object sender, CustomDrawSeriesPointEventArgs e){
DashboardFlatDataSourceRow row = e.SeriesPoint.Tag as DashboardFlatDataSourceRow;
string formattedValue = flatData.GetDisplayText(dashboardItem.Metadata.Value.UniqueId, row);
e.LabelText = e.SeriesPoint.Argument + " - " + formattedValue;
e.LegendText = e.SeriesPoint.Argument;
}
Visualize a Custom Item in a Dashboard
Assign the FunnelItemControlProvider
object to the e.CustomControlProvider property in a DashboardDesigner.CustomDashboardItemControlCreating event handler to visualize the custom control.
using System.Windows.Forms;
using TutorialsCustomItems.CustomItems;
using DevExpress.DashboardCommon;
using DevExpress.DashboardWin;
namespace TutorialsCustomItems {
public partial class Form1 : Form {
dashboardDesigner1.CustomDashboardItemControlCreating += DashboardDesigner1_CustomDashboardItemControlCreating;
// ...
private void DashboardDesigner1_CustomDashboardItemControlCreating(object sender,
CustomDashboardItemControlCreatingEventArgs e){
if (e.MetadataType == typeof(FunnelItemMetadata))
e.CustomControlProvider = new FunnelItemControlProvider(dashboardDesigner1.Dashboard.Items[e.DashboardItemName] as CustomDashboardItem<FunnelItemMetadata>);
}
}
}
Export a Custom Item
You can export custom dashboard items in the following formats:
- Image
- Excel (XLS, XLSX)
Refer to the following help topic for more information on how to configure export of custom dashboard items to different formats: Custom Item Export.
To export the custom Funnel item to Image or PDF, override the CustomControlProviderBase.GetPrintableControl method to obtain the printable control.
using DevExpress.XtraReports.UI;
using DevExpress.DashboardCommon;
namespace TutorialsCustomItems {
public class FunnelItemControlProvider : CustomControlProviderBase {
protected override XRControl GetPrintableControl(CustomItemData customItemData, CustomItemExportInfo info) {
PrintableComponentContainer container = new PrintableComponentContainer();
container.PrintableComponent = chart;
return container;
}
}
}
Run the Project to See the Result
Run the project and click the Funnel button in the Ribbon to add the custom item to the dashboard:
This action adds the custom item to the dashboard’s layout:
Drag data fields from the Data Source Browser and drop them onto the appropriate section in the binding panel to supply the custom item with data.
Next Step
Refer to the following tutorial for more information on how to create a custom Boolean property that manages the Funnel legend’s visibility:
Example
The following example shows how to implement a custom dashboard item in a WinForms application. The example contains custom items that you get once the tutorials are completed. You can find the Funnel item’s source code in this project.