Skip to content

Commit e59080e

Browse files
NickVolynkindmitry-eliseev-devexpressAbadzhevIlia-Nenashev-devX
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 Co-authored-by: Dmitry Eliseev <dmitry.eliseev@devexpress.com> Co-authored-by: Vladimir Abadzhev <vladimira@devexpress.com> Co-authored-by: Ilia Nenashev <ilia.nenashev@devexpress.com>
1 parent b53efd8 commit e59080e

13 files changed

+283
-17
lines changed

.github/meta.yml

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,4 @@
22
url: vcl-dashboards-store-layout-template-database
33
website: https://docs.devexpress.com/VCL/405642/ExpressDashboards/vcl-dashboards
44
tags: [vcl, dashboards, layout, database]
5-
description: |
6-
DevExpress VCL Dashboards - Store Dashboard Layouts in a Database
5+
description: "DevExpress Dashboards for Delphi/C++Builder - Store Dashboard Layouts and User Interaction State in a Database"
-59.5 KB
Binary file not shown.

README.md

Lines changed: 282 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,33 +5,300 @@
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 User Interaction 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 allows users to create new layouts/modify existing layouts
11+
(using the built-in Dashboard Designer), interact with dashboard UI elements, and save
12+
[state][TdxCustomDashboardControl.State] or [layout][TdxCustomDashboardControl.Layout] changes to the data source.
13+
14+
![DevExpress Dashboards for Delphi/C++Builder - Database Layout Storage Example](./images/vcl-dashboard-layout-database-sample-app.png)
1115

12-
![DevExpress VCL Dashboards - Database Layout Storage Example](/Images/vcl-dashboard-layout-database-sample-app.png)
1316

1417
## Prerequisites
1518

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
19+
[DevExpress Dashboards Prerequisites][req]
20+
21+
[req]: https://docs.devexpress.com/VCL/405773/ExpressCrossPlatformLibrary/vcl-backend/reports-dashboards-app-deployment#vcl-reportsdashboards-prerequisites
22+
1923

2024
## Test the Example
2125

22-
1. Run the sample app.
23-
2. Click **New Dashboard** to create a new dashboard and a dataset record. Alternatively, you can click **Design Dashboard** to modify the existing dashboard.
24-
3. Create or modify the dashboard layout using tools available within the UI.
25-
4. Click the hamburger button, select the **Save** option, and close the dialog.
26-
5. Close the app. The [TdxMemData](https://docs.devexpress.com/VCL/dxmdaset.TdxMemData) component will store layout data between sessions.
27-
6. Run the sample again. Click on grid records to switch between loaded dashboards.
26+
1. Run the sample app.
27+
1. Click **New Dashboard** to create a new dashboard or **Design Dashboard** to modify the pre-defined dashboard.
28+
1. Create or modify the dashboard layout using tools available within the UI.
29+
1. Click the hamburger button, select the **Save** option, and close the dialog.
30+
1. Create additional layouts if necessary.
31+
1. Close and restart the app.
32+
Click on grid records to switch between dashboard layouts you set up previously.
33+
Press **Design Dashboard** or **Delete Dashboard** to modify or delete entries.
34+
35+
![DevExpress Dashboards for Delphi/C++Builder — Store Dashboard Layout Definitions in a Database](./images/vcl-dashboards-store-layout-template-database.gif)
36+
37+
38+
## Implementation Details
39+
40+
The example stores dashboard layouts using a DevExpress memory-based dataset ([TdxMemData]).
41+
You can modify the application to use any other [TDataSet] descendant instead.
42+
To review our data module implementation, see the following file: [uData.pas]/[uData.cpp].
43+
44+
The instructions assume that you start with a Delphi or C++Builder project that already includes
45+
a configured data source for DevExpress Dashboards.
46+
This example application uses a memory-based dataset as the dashboard's data source
47+
(see `mdRevenueByIndustry` in the data module).
48+
To configure a dashboard data source in your project, refer to the following tutorial:
49+
[Create a dashboard using the Designer Dialog][designer].
50+
51+
### Step 1: Create a Dataset to Store Dashboard Layout and State Data
52+
53+
1. Add a [TdxMemData] component to the data module (`mdLayouts` in the example).
54+
1. Add a [TDataSource] component to the data module (`dsLayouts` in the example).
55+
Assign the previously created dataset component to `TDataSource.DataSet`:
56+
57+
> <img src="./images/create-bind-data-source.png" style="width: 50%"
58+
alt="Object Inspector panel displaying TDataSource properties."/>
59+
60+
1. Open the context menu for the dataset component and select **Field Editor…**:
61+
62+
> <img src="./images/open-context-menu.png" style="width: 50%"
63+
alt="Context menu for the TdxMemData component displaying a 'Field Editor' option."/>
64+
65+
1. Click **Add…** to create a BLOB field ([ftBlob]) for layout data:
66+
67+
> <img src="./images/create-layout-field.png" style="width: 50%"
68+
alt="New Field dialog adding a 'Layout' field of type ftBlob"/>
69+
70+
1. Click **Add…** to create a string field ([ftWideString]) for layout names:
71+
72+
> <img src="./images/create-name-field.png" style="width: 50%"
73+
alt="New Field dialog adding a 'Name' field of type ftWideString"/>
74+
75+
1. Click **Add…** to create another BLOB field for dashboard states:
76+
77+
> <img src="./images/create-state-field.png" style="width: 50%"
78+
alt="New Field dialog adding a 'State' field of type ftBlob"/>
79+
80+
1. (*Optional*) Preload persistent data to the dataset to make layouts available in the application upon first launch.
81+
82+
This example includes a sample dashboard layout that displays revenue data from an included dataset.
83+
You can preload dashboard layout and data from [layout.dat] and [revenue.dat], respectively.
84+
Open the context menu for the dataset component, select **Persistent Editor…**, click **Load…**, and select the file.
85+
86+
> <img src="./images/create-persistent-data.png" style="width: 50%"
87+
alt="Context menu for the TdxMemData component displaying a 'Persistent Editor' option."/>
88+
89+
Alternatively, you can use the Dashboard Designer later to import dashboard data from an XML file.
90+
91+
92+
## Step 2: Load a Dashboard Layout Definition
93+
94+
To load a layout definition to the Dashboard Control ([TdxCustomDashboardControl]), you must specify
95+
dashboard name ([TdxCustomDashboardControl.DashboardName]), layout ([TdxCustomDashboardControl.Layout]),
96+
and, optionally, dashboard user interaction state ([TdxCustomDashboardControl.State]):
97+
98+
<!-- start-code-block -->
99+
#### Delphi
100+
101+
```delphi
102+
procedure TMainForm.LoadLayoutDefinition;
103+
begin
104+
// Ensure that the dataset has at least one record or a new record is being created
105+
if (DataModule1.mdLayouts.RecordCount = 0) and (DataModule1.mdLayouts.State <> dsInsert) then
106+
begin
107+
dxDashboardControl1.Clear;
108+
Exit;
109+
end;
110+
// Load dashboard name and layout from the database
111+
dxDashboardControl1.DashboardName := DataModule1.mdLayoutsName.AsString;
112+
dxDashboardControl1.Layout.Assign(DataModule1.mdLayoutsLayout);
113+
// Load a dashboard state if it is stored in the database
114+
if not DataModule1.mdLayoutsState.IsNull then
115+
dxDashboardControl1.State.Assign(DataModule1.mdLayoutsState);
116+
end;
117+
```
118+
<!-- end-code-block -->
119+
120+
To load a different dashboard in the Dashboard Control, assign a new dashboard name and layout.
121+
The assigned dashboard replaces the current layout definition and resets the dashboard state.
122+
123+
You can also clear the Dashboard Control using [TdxCustomDashboardControl.Clear].
124+
125+
126+
### Step 3: Display the Dashboard Designer
127+
128+
Once you assign a dashboard layout definition to the Dashboard Control,
129+
you can display the [Dashboard Designer][designer] dialog:
130+
131+
<!-- start-code-block -->
132+
#### Delphi
133+
134+
```delphi
135+
procedure TMainForm.btnDesignClick(Sender: TObject);
136+
begin
137+
dxDashboardControl1.ShowDesigner; // Displays the Dashboard Designer
138+
end;
139+
```
140+
<!-- end-code-block -->
141+
142+
### Step 4: Store Dashboard State in a Dataset
143+
144+
When a user interacts with the dashboard in the Dashboard Control or Designer,
145+
the value of [TdxCustomDashboardControl.State] changes and an
146+
[OnStateChanged][TdxCustomDashboardControl.OnStateChanged] event is called.
147+
Handle this event to save dashboard state changes to the database.
148+
149+
<!-- start-code-block -->
150+
#### Delphi
151+
152+
```delphi
153+
procedure TMainForm.dxDashboardControl1StateChanged(
154+
ASender: TdxCustomDashboardControl);
155+
begin
156+
// Start editing the active dataset record
157+
DataModule1.mdLayouts.Edit;
158+
159+
// Save the current dashboard state to the active record
160+
DataModule1.mdLayoutsState.Assign(dxDashboardControl1.State);
161+
162+
// Finish editing and post the modified record to the database
163+
DataModule1.mdLayouts.Post;
164+
end;
165+
```
166+
<!-- end-code-block -->
167+
168+
### Step 5: Store Dashboard Layouts in a Dataset
169+
170+
When a user edits and saves a dashboard in the Dashboard Designer,
171+
the value of [TdxCustomDashboardControl.Layout] changes and an
172+
[OnLayoutChanged][TdxCustomDashboardControl.OnLayoutChanged] event is called.
173+
Handle this event to save layout changes to the database.
174+
175+
<!-- start-code-block -->
176+
#### Delphi
177+
178+
```delphi
179+
procedure TMainForm.dxDashboardControl1LayoutChanged(
180+
ASender: TdxCustomDashboardControl);
181+
begin
182+
if DataModule1.mdLayoutsName.AsString <> dxDashboardControl1.DashboardName then
183+
begin
184+
// Create and start editing a new dataset record
185+
DataModule1.mdLayouts.Append;
186+
DataModule1.mdLayoutsName.AsString := dxDashboardControl1.DashboardName;
187+
end
188+
else
189+
// Start editing the active dataset record
190+
DataModule1.mdLayouts.Edit;
191+
192+
// Save the dashboard layout to the database
193+
DataModule1.mdLayoutsLayout.Assign(dxDashboardControl1.Layout);
194+
// Finish editing and post the modified record to the database:
195+
DataModule1.mdLayouts.Post;
196+
end;
197+
```
198+
<!-- end-code-block -->
199+
200+
### Step 6: Persist Data between Application Sessions
201+
202+
This step is applicable only to the memory-based [TdxMemData] datasource.
203+
204+
To save the dataset to a file and restore data on app restart,
205+
handle `OnCreate` and `OnDestroy` events of the data module:
206+
207+
<!-- start-code-block -->
208+
#### Delphi
209+
210+
```delphi
211+
const
212+
DataFileName = 'data.dat';
213+
214+
procedure TDataModule1.DataModuleCreate(Sender: TObject);
215+
begin
216+
if FileExists(DataFileName) then
217+
mdLayouts.LoadFromBinaryFile(DataFileName)
218+
end;
219+
220+
procedure TDataModule1.DataModuleDestroy(Sender: TObject);
221+
begin
222+
if mdLayouts.RecordCount > 0 then
223+
mdLayouts.SaveToBinaryFile(DataFileName)
224+
end;
225+
```
226+
<!-- end-code-block -->
227+
228+
## Files to Review
229+
230+
- [uData.pas]/[uData.cpp] — stores dashboard layouts and supplies data to the dashboard.
231+
- [uMainForm.pas]/[uMainForm.cpp] — loads dashboard layouts from the data module
232+
and displays Dashboard Control and Dashboard Designer.
233+
- [layout.dat] and [revenue.dat] — store memory-based dataset states you can load to reproduce this example.
234+
- [data.dat] — stores the memory-based dataset state between application sessions.
28235

29-
![DevExpress VCL Dashboards - Store Dashboard Layout Definitions in a Database](/Images/vcl-dashboards-store-layout-template-database.gif)
30236

31237
## Documentation
32238

33-
* [TdxCustomDashboardControl.Layout](https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Layout)
34-
* [TdxBackendDataSetJSONConnection](https://docs.devexpress.com/VCL/dxBackend.ConnectionString.JSON.DataSet.TdxBackendDataSetJSONConnection)
239+
- [Introduction to DevExpress Dashboards for Delphi/C++Builder][dashboards-intro]
240+
- [Tutorial: Create a dashboard using the Designer Dialog][designer]
241+
- [Use JSON as a data source for dashboards (as demonstrated in the current example)][json-data-source]
242+
- [Save the dashboard layout to file on every change (code example)][save-to-file]
243+
- API reference:
244+
- [TdxCustomDashboardControl] (used to display a dashboard on an application form)
245+
- [TdxCustomDashboardControl.State] (a JSON-based dashboard state you can store in a BLOB dataset field)
246+
- [TdxCustomDashboardControl.Layout] (an XML-based layout template you can store in a BLOB dataset field)
247+
- [TdxCustomDashboardControl.DashboardName] (internal dashboard name that is not included in the layout or state)
248+
- [TdxCustomDashboardControl.OnStateChanged] (event called when a user interacts with a dashboard and changes its state)
249+
- [TdxCustomDashboardControl.OnLayoutChanged] (event called when a user edits and saves a dashboard in the Dashboard Designer)
250+
- [TdxMemData] (DevExpress in-memory dataset implementation)
251+
- [TDataSet] (contains generic database connection methods)
252+
- [TdxBackendDataSetJSONConnection] (supplies data to dashboards)
253+
254+
255+
<!-- documentation links -->
256+
257+
[dashboards-intro]: https://docs.devexpress.com/VCL/405642/ExpressDashboards/vcl-dashboards
258+
[designer]: https://docs.devexpress.com/VCL/405774/ExpressDashboards/getting-started/create-dashboard-using-designer-dialog
259+
[json-data-source]: https://docs.devexpress.com/VCL/405747/ExpressCrossPlatformLibrary/vcl-backend/database-engines/vcl-backend-memory-based-data-storage
260+
[save-to-file]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Layout#save-dashboard-layout-to-file-on-every-change
261+
[supported-dbms]: https://docs.devexpress.com/VCL/405703/ExpressCrossPlatformLibrary/vcl-backend/vcl-backend-supported-database-systems
262+
263+
<!-- reference links -->
264+
[TdxCustomDashboardControl]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl
265+
[TdxCustomDashboardControl.Clear]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Clear
266+
[TdxCustomDashboardControl.DashboardName]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Layout
267+
[TdxCustomDashboardControl.Layout]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.Layout
268+
[TdxCustomDashboardControl.State]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.State
269+
[TdxCustomDashboardControl.OnLayoutChanged]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.OnLayoutChanged
270+
[TdxCustomDashboardControl.OnStateChanged]: https://docs.devexpress.com/VCL/dxDashboard.Control.TdxCustomDashboardControl.OnStateChanged
271+
[TdxBackendDataSetJSONConnection]: https://docs.devexpress.com/VCL/dxBackend.ConnectionString.JSON.DataSet.TdxBackendDataSetJSONConnection
272+
[TdxMemData]: https://docs.devexpress.com/VCL/dxmdaset.TdxMemData
273+
274+
275+
<!-- external documentation links -->
276+
[TDataSet]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TDataSet
277+
[TDataSource]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TDataSource
278+
[ftString]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TFieldType
279+
[ftWideString]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TFieldType
280+
[ftBlob]: https://docwiki.embarcadero.com/Libraries/Athens/en/Data.DB.TFieldType
281+
282+
283+
<!-- in-repository links -->
284+
[uData.pas]: ./Delphi/uData.pas
285+
[uData.cpp]: ./CPB/uData.cpp
286+
[data.dat]: ./Delphi/data.dat
287+
[layout.dat]: ./layout.dat
288+
[revenue.dat]: ./revenue.dat
289+
[uMainForm.pas]: ./Delphi/uMainForm.pas
290+
[uMainForm.cpp]: ./CPB/uMainForm.cpp
291+
292+
293+
## More Examples
294+
295+
- [Pass Hidden Parameters to a SQL Query][hidden-parameter-example]
296+
- [Generate Dashboards in a Backend / Service Application][non-interactive-example]
297+
- [Store Layouts in XML Files (DevExpress Reports for Delphi/C++Builder)][file-example]
298+
299+
[hidden-parameter-example]: https://github.com/DevExpress-Examples/vcl-dashboards-pass-hidden-parameters-to-custom-sql-query
300+
[file-example]: https://github.com/DevExpress-Examples/vcl-reports-store-layout-template-file
301+
[non-interactive-example]: https://github.com/DevExpress-Examples/vcl-reports-store-layout-template-database
35302

36303
<!-- feedback -->
37304
## 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

images/open-context-menu.png

13.1 KB
Loading
82.2 KB
Loading

0 commit comments

Comments
 (0)