如何将DevExpress VCL TdxLayoutControl配置存储至多数据库及INI格式?
问题描述
DevExpress VCL的TdxLayoutControl支持三种配置存储方式——INI文件、Windows注册表、TStream(可存入数据库BLOB)。其中INI文件为可读文本格式,后两者为二进制格式。我们希望同时实现以下需求:
- 将TdxLayoutControl的自定义配置存储到数据库BLOB字段;
- 以INI文本格式存储/读写操作该数据;
- 支持指定存储/读取的目标数据库(多租户/多数据库场景)。
现有方案及局限
- 使用
StoreToStream可实现需求1和3,但存储的是二进制数据,无法满足文本格式需求; - 通过重写
TcxIniFileReader和TcxIniFileWriter类,配合StoreToStorage可实现需求1和2,但只能通过全局变量获取数据库连接信息,无法灵活传递连接参数(容器负责实例化子类,仅能通过AStorageName参数传递,扩展性差)。
构想的解决方向
- 让
StoreToStream支持选择存储格式(二进制/INI文本); - 允许向
StoreToStorage方法传入已实例化的TcxIniFileReader/Writer子类; - 让
TcxIniFileReader/Writer子类可访问调用它的TdxLayoutContainer(我们尝试用Tag存储实例化信息); - 开发解析工具,将BLOB中的二进制数据转为INI格式,修改后再转回二进制存入BLOB。
二进制存储示例代码(StoreToStream实现)
Test.dpr
program Test; uses Vcl.Forms, Unit1 in 'Unit1.pas' {Form1}; {$R *.res} begin Application.Initialize; Application.MainFormOnTaskbar := True; Application.CreateForm(TForm1, Form1); Application.Run; end.
Unit1.pas
unit Unit1; interface uses Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics, Vcl.Controls, Vcl.Forms, Vcl.Dialogs, cxGraphics, cxControls, cxLookAndFeels, cxLookAndFeelPainters, dxSkinsCore, dxSkinBasic, // DevExpress Skins omitted ... dxLayoutcxEditAdapters, cxContainer, cxEdit, dxLayoutContainer, cxTextEdit, Data.DB, Data.Win.ADODB, cxClasses, dxLayoutControl, Vcl.Menus, Vcl.StdCtrls, cxButtons, Vcl.ExtCtrls; type TForm1 = class(TForm) lcMainGroup_Root: TdxLayoutGroup; lcMain: TdxLayoutControl; cxTextEdit1: TcxTextEdit; dxLayoutItem1: TdxLayoutItem; cxTextEdit2: TcxTextEdit; dxLayoutItem2: TdxLayoutItem; cxTextEdit3: TcxTextEdit; dxLayoutItem3: TdxLayoutItem; cxTextEdit4: TcxTextEdit; dxLayoutItem4: TdxLayoutItem; dxLayoutGroup1: TdxLayoutGroup; dxLayoutGroup2: TdxLayoutGroup; Panel1: TPanel; cxButton1: TcxButton; cxButton2: TcxButton; procedure FormCreate(Sender: TObject); procedure cxButton1Click(Sender: TObject); procedure cxButton2Click(Sender: TObject); private FADOConnection: TADOConnection; FADOQuery: TADOQuery; public { Public declarations } end; var Form1: TForm1; implementation {$R *.dfm} const LayoutName: string = 'TestLayout'; const FilterFormat: string = 'Name = ''%s'''; procedure TForm1.cxButton1Click(Sender: TObject); begin lcMain.Customization := True; end; procedure TForm1.cxButton2Click(Sender: TObject); var LStream: TMemoryStream; LField: TBlobField; begin FADOQuery.Open; FADOQuery.Edit; LStream := TMemoryStream.Create; try lcMain.Container.StoreToStream(LStream); LField := FADOQuery.FieldByName('DataMemo') as TBlobField; LField.LoadFromStream(LStream); FADOQuery.Post; finally FADOQuery.Close; LStream.Free; end; end; procedure TForm1.FormCreate(Sender: TObject); var LStream: TStream; LField: TField; begin FADOConnection := TADOConnection.Create(Self); FADOConnection.ConnectionString := 'Provider=SQLOLEDB.1;' + 'Integrated Security=SSPI;' + 'Persist Security Info=False;' + 'Initial Catalog=Test;' + 'Data Source=localhost\SQLEXPRESS'; FADOQuery := TADOQuery.Create(Self); FADOQuery.Connection := FADOConnection; FADOQuery.SQL.Add('SELECT * FROM [Layouts] WHERE [Name] = ''TestLayout'''); FADOQuery.Open; try if not FADOQuery.FieldByName('DataMemo').IsNull then begin LField := FADOQuery.FieldByName('DataMemo'); LStream := FADOQuery.CreateBlobStream(LField, bmRead); lcMain.Container.RestoreFromStream(LStream); end; finally FADOQuery.Close; end; end; end.
Unit1.dfm
object Form1: TForm1 Left = 0 Top = 0 Caption = 'Form1' ClientHeight = 441 ClientWidth = 624 Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -12 Font.Name = 'Segoe UI' Font.Style = [] OnCreate = FormCreate TextHeight = 15 object lcMain: TdxLayoutControl Left = 0 Top = 0 Width = 624 Height = 384 Align = alClient TabOrder = 0 object cxTextEdit1: TcxTextEdit Left = 92 Top = 33 Style.BorderColor = clWindowFrame Style.BorderStyle = ebs3D Style.HotTrack = False Style.TransparentBorder = False TabOrder = 0 Text = 'cxTextEdit1' Width = 121 end object cxTextEdit2: TcxTextEdit Left = 92 Top = 63 Style.BorderColor = clWindowFrame Style.BorderStyle = ebs3D Style.HotTrack = False Style.TransparentBorder = False TabOrder = 1 Text = 'cxTextEdit2' Width = 121 end object cxTextEdit3: TcxTextEdit Left = 92 Top = 128 Style.BorderColor = clWindowFrame Style.BorderStyle = ebs3D Style.HotTrack = False Style.TransparentBorder = False TabOrder = 2 Text = 'cxTextEdit3' Width = 121 end object cxTextEdit4: TcxTextEdit Left = 92 Top = 158 Style.BorderColor = clWindowFrame Style.BorderStyle = ebs3D Style.HotTrack = False Style.TransparentBorder = False TabOrder = 3 Text = 'cxTextEdit4' Width = 121 end object lcMainGroup_Root: TdxLayoutGroup AlignHorz = ahLeft AlignVert = avTop Hidden = True ItemIndex = 1 ShowBorder = False Index = -1 end object dxLayoutItem1: TdxLayoutItem Parent = dxLayoutGroup1 CaptionOptions.Text = 'cxTextEdit1' Control = cxTextEdit1 ControlOptions.OriginalHeight = 23 ControlOptions.OriginalWidth = 121 ControlOptions.ShowBorder = False Index = 0 end object dxLayoutItem2: TdxLayoutItem Parent = dxLayoutGroup1 CaptionOptions.Text = 'cxTextEdit2' Control = cxTextEdit2 ControlOptions.OriginalHeight = 23 ControlOptions.OriginalWidth = 121 ControlOptions.ShowBorder = False Index = 1 end object dxLayoutItem3: TdxLayoutItem Parent = dxLayoutGroup2 CaptionOptions.Text = 'cxTextEdit3' Control = cxTextEdit3 ControlOptions.OriginalHeight = 23 ControlOptions.OriginalWidth = 121 ControlOptions.ShowBorder = False Index = 0 end object dxLayoutItem4: TdxLayoutItem Parent = dxLayoutGroup2 CaptionOptions.Text = 'cxTextEdit4' Control = cxTextEdit4 ControlOptions.OriginalHeight = 23 ControlOptions.OriginalWidth = 121 ControlOptions.ShowBorder = False Index = 1 end object dxLayoutGroup1: TdxLayoutGroup Parent = lcMainGroup_Root CaptionOptions.Text = 'New Group' Index = 0 end object dxLayoutGroup2: TdxLayoutGroup Parent = lcMainGroup_Root CaptionOptions.Text = 'New Group' ItemIndex = 1 Index = 1 end end object Panel1: TPanel Left = 0 Top = 384 Width = 624 Height = 57 Align = alBottom Caption = 'Panel1' ShowCaption = False TabOrder = 1 object cxButton1: TcxButton Left = 16 Top = 16 Width = 75 Height = 25 Caption = 'Customize' TabOrder = 0 OnClick = cxButton1Click end object cxButton2: TcxButton Left = 488 Top = 16 Width = 123 Height = 25 Caption = 'Save Customization' TabOrder = 1 OnClick = cxButton2Click end end end
内容的提问来源于stack exchange,提问作者Jason Goble
相关产品推荐
相关产品推荐

