Skip to content

Commit cc5f083

Browse files
committed
readme: Add implementation details and reference
- Add a step-by-step instruction with screenshots - Add more reference links to DevExpress and standard VCL library - Update repository description - Add layout.dat and revenue.dat files that store memory-based datasets that can be used to reproduce the example
1 parent aa640a7 commit cc5f083

13 files changed

+232
-10
lines changed

.github/meta.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@ url: vcl-dashboards-store-layout-template-database
33
website: https://docs.devexpress.com/VCL/405642/ExpressDashboards/vcl-dashboards
44
tags: [vcl, dashboards, layout, database]
55
description: |
6-
DevExpress VCL Dashboards - Store Dashboard Layouts in a Database
6+
DevExpress Dashboards for Delphi/C++Builder - Store Dashboard Layouts in a Database

Delphi/layout.dat

4.3 KB
Binary file not shown.

Delphi/revenue.dat

91.3 KB
Binary file not shown.
-59.5 KB
Binary file not shown.

README.md

Lines changed: 231 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,22 @@
55
[![](https://img.shields.io/badge/💬_Leave_Feedback-feecdd?style=flat-square)](#does-this-example-address-your-development-requirementsobjectives)
66
<!-- default badges end -->
77

8-
# DevExpress VCL Dashboards — Store Dashboard Layouts in a Database
8+
# DevExpress Dashboards for Delphi/C++Builder — Store Dashboard Layouts and State in a Database
99

10-
This sample app stores a [dashboard layout](https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Layout) (XML-based template) in the BLOB field of a memory-based dataset ([TdxMemData](https://docs.devexpress.com/VCL/dxmdaset.TdxMemData) inherited from the [TDataSet](https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TDataSet) class shipped with the standard VCL library).
10+
This example application stores [DevExpress dashboard layouts][TdxCustomDashboardControl.Layout]
11+
in a database.
12+
The sample allows users to create new layouts, modify existing layouts using the built-in
13+
Dashboard Designer, interact with dashboards, and save state or layout changes to the data source.
14+
15+
> ![DevExpress VCL Dashboards - Database Layout Storage Example](./images/vcl-dashboard-layout-database-sample-app.png)
1116
12-
![DevExpress VCL Dashboards - Database Layout Storage Example](/Images/vcl-dashboard-layout-database-sample-app.png)
1317

1418
## Prerequisites
1519

16-
* Microsoft Windows 10 or newer
17-
* Embarcadero RAD Studio IDE 12.3 (Athens) or newer (Community Edition is not supported)
18-
* DevExpress VCL Components v25.2.3 or newer
20+
[DevExpress Dashboards Prerequisites][req]
21+
22+
[req]: https://docs.devexpress.com/VCL/405773/ExpressCrossPlatformLibrary/vcl-backend/reports-dashboards-app-deployment#vcl-reportsdashboards-prerequisites
23+
1924

2025
## Test the Example
2126

@@ -26,12 +31,229 @@ This sample app stores a [dashboard layout](https://docs.devexpress.com/VCL/dxDa
2631
5. Close the app. The [TdxMemData](https://docs.devexpress.com/VCL/dxmdaset.TdxMemData) component will store layout data between sessions.
2732
6. Run the sample again. Click on grid records to switch between loaded dashboards.
2833

29-
![DevExpress VCL Dashboards - Store Dashboard Layout Definitions in a Database](/Images/vcl-dashboards-store-layout-template-database.gif)
34+
> ![DevExpress VCL Dashboards — Store Dashboard Layout Definitions in a Database](./images/vcl-dashboards-store-layout-template-database.gif)
35+
36+
37+
## Implementation Details
38+
39+
The example uses a DevExpress memory-based dataset for dashboard layout storage: [TdxMemData].
40+
You can modify the application to use any other [TDataSet] descendant instead.
41+
To review our data module implementation, see the following file: [uData.pas]/[uData.cpp].
42+
43+
The instructions assume that you start with a Delphi or C++Builder project that already includes
44+
a configured data source for DevExpress Dashboards.
45+
The example uses a memory-based dataset as the dashboard's data source
46+
(see `mdRevenueByIndustry` in the data module).
47+
To configure a dashboard data source in your project, refer to the following tutorial:
48+
[Create a dashboard using the Designer Dialog][designer].
49+
50+
### Step 1: Create a Dataset to Store Dashboard Layout and State Data
51+
52+
1. Add a [TdxMemData] component to the data module (`mdLayouts` in the example).
53+
1. Add a [TDataSource] component to the data module (`dsLayouts` in the example).
54+
Assign the previously created dataset component to `TDataSource.DataSet`:
55+
56+
> <img src="./images/create-bind-data-source.png" style="width: 50%"
57+
alt="Object Inspector panel displaying TDataSource properties."/>
58+
59+
1. Open the context menu for the dataset component and select **Field Editor…**:
60+
61+
> <img src="./images/open-context-menu.png" style="width: 50%"
62+
alt="Context menu for the TdxMemData component displaying a 'Field Editor' option."/>
63+
64+
1. Click **Add…** to create a BLOB field for layout data ([]):
65+
66+
> <img src="./images/create-layout-field.png" style="width: 50%"
67+
alt="New Field dialog adding a 'Layout' field of type ftBlob"/>
68+
69+
1. Click **Add…** to create a string field for layout names:
70+
71+
> <img src="./images/create-name-field.png" style="width: 50%"
72+
alt="New Field dialog adding a 'Name' field of type ftWideString"/>
73+
74+
1. Click **Add…** to create another BLOB field for dashboard stats:
75+
76+
> <img src="./images/create-state-field.png" style="width: 50%"
77+
alt="New Field dialog adding a 'State' field of type ftBlob"/>
78+
79+
1. (*Optional*) Preload persistent data to the dataset to make layouts available in the application upon first launch.
80+
81+
This example includes a sample dashboard layout that displays revenue data from an included dataset.
82+
You can preload the layout and revenue from [layout.dat] and [revenue.dat] respectively.
83+
Open the context menu for the dataset component, select **Persistent Editor…**, click **Load…**, and select the file.
84+
85+
> <img src="./images/create-persistent-data.png" style="width: 50%"
86+
alt="Context menu for the TdxMemData component displaying a 'Persistent Editor' option."/>
87+
88+
Alternatively, you can use the Dashboard Designer later to import dashboard data from an XML file.
89+
90+
91+
## Step 2: Load a Dashboard Layout Definition
92+
93+
To load a layout definition to the Dashboard Control ([TdxCustomDashboardControl]), you must specify
94+
dashboard name ([TdxCustomDashboardControl.DashboardName]), layout ([TdxCustomDashboardControl.Layout]),
95+
and, optionally, dashboard user interaction state ([TdxCustomDashboardControl.State]):
96+
97+
```pas
98+
procedure TMainForm.LoadLayoutDefinition;
99+
begin
100+
// Ensure that the dataset has at least one record or a new record is being created:
101+
if (DataModule1.mdLayouts.RecordCount = 0) and (DataModule1.mdLayouts.State <> dsInsert) then
102+
begin
103+
dxDashboardControl1.Clear;
104+
Exit;
105+
end;
106+
// Load dashboard name and layout from the database:
107+
dxDashboardControl1.DashboardName := DataModule1.mdLayoutsName.AsString;
108+
dxDashboardControl1.Layout.Assign(DataModule1.mdLayoutsLayout);
109+
// Load dashboard state if it is stored in the database:
110+
if not DataModule1.mdLayoutsState.IsNull then
111+
dxDashboardControl1.State.Assign(DataModule1.mdLayoutsState);
112+
end;
113+
```
114+
115+
To load a different dashboard in the Dashboard Control, assign a new dashboard name and layout.
116+
The assigned dashboard replaces the current layout definition and resets the dashboard state.
117+
118+
You can also clear the Dashboard Control using [TdxCustomDashboardControl.Clear].
119+
120+
121+
### Step 3: Display the Dashboard Designer
122+
123+
Once you assigned a dashboard layout definition to the Dashboard Control,
124+
you can display the [Dashboard Designer][designer] dialog:
125+
126+
```pas
127+
procedure TMainForm.btnDesignClick(Sender: TObject);
128+
begin
129+
dxDashboardControl1.ShowDesigner; // Displays the Dashboard Designer
130+
end;
131+
```
132+
133+
### Step 4: Store Dashboard State in a Dataset
134+
135+
When a user interacts with the dashboard in the Dashboard Control or Designer,
136+
the value of [TdxCustomDashboardControl.State] changes and an
137+
[OnStateChanged][TdxCustomDashboardControl.OnStateChanged] event is called.
138+
Handle this event to save dashboard state changes to the database.
139+
140+
```pas
141+
procedure TMainForm.dxDashboardControl1StateChanged(
142+
ASender: TdxCustomDashboardControl);
143+
begin
144+
// Start editing the active dataset record:
145+
DataModule1.mdLayouts.Edit;
146+
147+
// Save the current dashboard state to the active record:
148+
DataModule1.mdLayoutsState.Assign(dxDashboardControl1.State);
149+
150+
// Finish editing and post the modified record to the database:
151+
DataModule1.mdLayouts.Post;
152+
end;
153+
```
154+
155+
### Step 5: Store Dashboard Layouts in a Dataset
156+
157+
When a user edits and saves a dashboard in the Dashboard Designer,
158+
the value of [TdxCustomDashboardControl.Layout] changes and an
159+
[OnLayoutChanged][TdxCustomDashboardControl.OnLayoutChanged] event is called.
160+
Handle this event to save layout changes to the database.
161+
162+
```pas
163+
procedure TMainForm.dxDashboardControl1LayoutChanged(
164+
ASender: TdxCustomDashboardControl);
165+
begin
166+
if DataModule1.mdLayoutsName.AsString <> dxDashboardControl1.DashboardName then
167+
begin
168+
// Create and start editing a new dataset record
169+
DataModule1.mdLayouts.Append;
170+
DataModule1.mdLayoutsName.AsString := dxDashboardControl1.DashboardName;
171+
end
172+
else
173+
// Start editing the active dataset record
174+
DataModule1.mdLayouts.Edit;
175+
176+
// Save dashboard layout to the database:
177+
DataModule1.mdLayoutsLayout.Assign(dxDashboardControl1.Layout);
178+
// Finish editing and post the modified record to the database:
179+
DataModule1.mdLayouts.Post;
180+
end;
181+
```
182+
183+
## Files to Review
184+
185+
- [uData.pas]/[uData.cpp] stores dashboard layouts and supplies data to the dashboard.
186+
- [uMainForm.pas]/[uMainForm.cpp] loads dashboard layouts from the data module,
187+
and displays Dashboard Control and Dashboard Designer.
188+
- [layout.dat] and [revenue.dat] store memory-based dataset states that you can load to reproduce this example.
189+
- [data.dat] stores the memory-based dataset state between application sessions.
190+
30191

31192
## Documentation
32193

33-
* [TdxCustomDashboardControl.Layout](https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Layout)
34-
* [TdxBackendDataSetJSONConnection](https://docs.devexpress.com/VCL/dxBackend.ConnectionString.JSON.DataSet.TdxBackendDataSetJSONConnection)
194+
- [Introduction to VCL Dashboards][dashboards-intro]
195+
- [Tutorial: Create a dashboard using the Designer Dialog][designer]
196+
- [Use JSON as a data source for dashboards (as demonstrated in the current example)][json-data-source]
197+
- [Save dashboard layout to file on every change (code example)][save-to-file]
198+
- API reference:
199+
- [TdxCustomDashboardControl] (used to display a dashboard in an application form)
200+
- [TdxCustomDashboardControl.State] (a JSON-based representation of dashboard state that can be stored in a BLOB data field)
201+
- [TdxCustomDashboardControl.Layout] (an XML-based layout template that can be stored in a BLOB data field)
202+
- [TdxCustomDashboardControl.DashboardName] (internal dashboard name that is not included in the layout or state)
203+
- [TdxCustomDashboardControl.OnStateChanged] (event called when user interacts with a dashboard and changes its state)
204+
- [TdxCustomDashboardControl.OnLayoutChanged] (event called when user edits and saves a dashboard in the Dashboard Designer)
205+
- [TdxMemData] (DevExpress in-memory dataset implementation)
206+
- [TDataSet] (contains generic database connection methods)
207+
- [TdxBackendDataSetJSONConnection] (supplies data to dashboards)
208+
209+
210+
<!-- documentation links -->
211+
212+
[dashboards-intro]: https://docs.devexpress.com/VCL/405642/ExpressDashboards/vcl-dashboards
213+
[designer]: https://docs.devexpress.com/VCL/405774/ExpressDashboards/getting-started/create-dashboard-using-designer-dialog
214+
[json-data-source]: https://docs.devexpress.com/VCL/405747/ExpressCrossPlatformLibrary/vcl-backend/database-engines/vcl-backend-memory-based-data-storage
215+
[save-to-file]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Layout#save-dashboard-layout-to-file-on-every-change
216+
[supported-dbms]: https://docs.devexpress.com/VCL/405703/ExpressCrossPlatformLibrary/vcl-backend/vcl-backend-supported-database-systems
217+
218+
<!-- reference links -->
219+
[TdxCustomDashboardControl]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl
220+
[TdxCustomDashboardControl.Clear]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Clear
221+
[TdxCustomDashboardControl.DashboardName]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Layout
222+
[TdxCustomDashboardControl.Layout]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Layout
223+
[TdxCustomDashboardControl.State]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.State
224+
[TdxCustomDashboardControl.OnLayoutChanged]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.OnLayoutChanged
225+
[TdxCustomDashboardControl.OnStateChanged]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.OnStateChanged
226+
[TdxBackendDataSetJSONConnection]: https://docs.devexpress.com/VCL/dxBackend.ConnectionString.JSON.DataSet.TdxBackendDataSetJSONConnection
227+
[TdxMemData]: https://docs.devexpress.com/VCL/dxmdaset.TdxMemData
228+
229+
230+
<!-- external documentation links -->
231+
[TDataSet]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TDataSet
232+
[TDataSource]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TDataSource
233+
[ftString]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TFieldType
234+
[ftWideString]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TFieldType
235+
[ftBlob]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TFieldType
236+
237+
238+
<!-- in-repository links -->
239+
[uData.pas]: ./Delphi/uData.pas
240+
[uData.cpp]: ./CPB/uData.cpp
241+
[data.dat]: ./Delphi/data.dat
242+
[layout.dat]: ./Delphi/layout.dat
243+
[revenue.dat]: ./Delphi/revenue.dat
244+
[uMainForm.pas]: ./Delphi/uMainForm.pas
245+
[uMainForm.cpp]: ./CPB/uMainForm.cpp
246+
247+
248+
## More Examples
249+
250+
- [Pass Hidden Parameters to a SQL Query][hidden-parameter-example]
251+
- [Generate Dashboards in a Backend / Service Application][non-interactive-example]
252+
- [Store Layouts in XML Files (DevExpress Reports for Delphi/C++Builder)][file-example]
253+
254+
[hidden-parameter-example]: https://github.com/DevExpress-Examples/vcl-dashboards-pass-hidden-parameters-to-custom-sql-query
255+
[file-example]: https://github.com/DevExpress-Examples/vcl-reports-store-layout-template-file
256+
[non-interactive-example]: https://github.com/DevExpress-Examples/vcl-reports-store-layout-template-database
35257

36258
<!-- feedback -->
37259
## Does This Example Address Your Development Requirements/Objectives?

images/create-bind-data-source.png

26.7 KB
Loading

images/create-layout-field.png

33.9 KB
Loading

images/create-name-field.png

34.2 KB
Loading

images/create-persistent-data.png

13.5 KB
Loading

images/create-state-field.png

22.3 KB
Loading

0 commit comments

Comments
 (0)