You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.20 03:05:54