Delphi 如何找出哪些DB感知控件链接到TDataSource?

Delphi 如何找出哪些DB感知控件链接到TDataSource?,delphi,delphi-7,Delphi,Delphi 7,我有DataSource1(TDataSource),并且有一些数据库感知控件链接到它(通过SomeDBControl.DataSource=DataSource1) 如何在代码中找出(枚举)哪些控件链接到给定的TDataSource?下面的代码使用RTTI,通过递归搜索容器对象(即表单及其组件),在D7中列出具有DataSource或MasterSource属性的组件 (显然,您可以对感兴趣的任何其他表单/数据模块执行类似操作) 更新#1:此答案的原始版本生成了表单上每个组件的列表及其数据源/

我有
DataSource1(TDataSource)
,并且有一些数据库感知控件链接到它(通过
SomeDBControl.DataSource=DataSource1


如何在代码中找出(枚举)哪些控件链接到给定的TDataSource?

下面的代码使用RTTI,通过递归搜索容器对象(即表单及其组件),在D7中列出具有DataSource或MasterSource属性的组件

(显然,您可以对感兴趣的任何其他表单/数据模块执行类似操作)

更新#1:此答案的原始版本生成了表单上每个组件的列表及其数据源/主源的名称(如果有)。我对它进行了更改,以便更好地匹配您在q)正文中提出的要求

更新#2:这修复了更新#1版本中的几个错误,并以一种避免在检查不具有DataSource/MasterSource属性的组件时生成异常的方式重新实现了HasDataSource函数

function HasDataSource(AComponent : TComponent; var ADataSource : TDataSource) : Boolean;

  function GetDataSource(APropName : String) : TDataSource;
  var
    AObject : TObject;
    PInfo : PPropInfo;
  begin
    Result :=  Nil;
    PInfo := GetPropInfo(AComponent, APropName);
    if PInfo = Nil then
      exit;
    AObject := GetObjectProp(AComponent, PInfo);
    Result := TDataSource(AObject);
  end;

begin
  Result :=  False;
  ADataSource := GetDataSource('DataSource');
  if ADataSource <> Nil then
    Result := True;
  if Result then exit;

  ADataSource := GetDataSource('MasterSource');
  if ADataSource <> Nil then
    Result := True;
end;


procedure TForm1.Log(Msg: String);
begin
  Memo1.Lines.Add(Msg);
end;

procedure TForm1.FindDataSourceObjects(AContainer : TComponent);
var
  i : Integer;
  ADataSource : TDataSource;

  procedure LogDataSourceName(AContainer : TComponent);
  begin
    Log(AContainer.Name + ' Datasource: ' + ADataSource.Name);
  end;

begin
  if HasDataSource(AContainer, ADataSource) then
    LogDataSourceName(AContainer);

  for i := 0 to AContainer.ComponentCount - 1 do begin
    FindDataSourceObjects(AContainer.Components[i]);
  end;
end;

procedure TForm1.btnFindClick(Sender: TObject);
begin
  FindDataSourceObjects(Self);
end;
函数HasDataSource(AComponent:TComponent;var-ADataSource:TDataSource):布尔;
函数GetDataSource(APropName:String):TDataSource;
变量
a对象:对象;
PInfo:PPropInfo;
开始
结果:=无;
PInfo:=GetPropInfo(一个组件,APropName);
如果PInfo=Nil,则
出口
AOObject:=GetObjectProp(组件,PInfo);
结果:=TDataSource(AOObject);
结束;
开始
结果:=假;
ADataSource:=GetDataSource('DataSource');
如果ADataSource为零,则
结果:=真;
如果有结果则退出;
ADataSource:=GetDataSource('MasterSource');
如果ADataSource为零,则
结果:=真;
结束;
过程TForm1.Log(消息:字符串);
开始
备忘录1.行。添加(Msg);
结束;
程序TForm1.FindDataSourceObject(容器:TComponent);
变量
i:整数;
ADataSource:TDataSource;
过程日志数据源名称(容器:TComponent);
开始
日志(AContainer.Name+'Datasource:'+ADataSource.Name);
结束;
开始
如果HasDataSource(一个容器,ADataSource),那么
日志数据源名称(容器);
对于i:=0到AContainer.ComponentCount-1,请开始
FindDataSourceObject(容器组件[i]);
结束;
结束;
程序TForm1.btnFindClick(发送方:TObject);
开始
FindDatasourceObject(自);
结束;
我表格中的DFM是

object Form1: TForm1
  Left = 195
  Top = 124
  Width = 623
  Height = 303
  Caption = 'Form1'
  Color = clBtnFace
  Font.Charset = DEFAULT_CHARSET
  Font.Color = clWindowText
  Font.Height = -11
  Font.Name = 'MS Sans Serif'
  Font.Style = []
  OldCreateOrder = False
  PixelsPerInch = 96
  TextHeight = 13
  object DBText1: TDBText
    Left = 307
    Top = 56
    Width = 65
    Height = 17
    DataSource = DataSource1
  end
  object Panel1: TPanel
    Left = 307
    Top = 80
    Width = 281
    Height = 161
    Caption = 'Panel1'
    TabOrder = 0
    object DBText2: TDBText
      Left = 24
      Top = 64
      Width = 65
      Height = 17
      DataSource = DataSource2
    end
  end
  object Memo1: TMemo
    Left = 8
    Top = 16
    Width = 281
    Height = 225
    TabOrder = 1
  end
  object btnFind: TButton
    Left = 307
    Top = 16
    Width = 75
    Height = 25
    Caption = 'Find'
    TabOrder = 2
    OnClick = btnFindClick
  end
  object DataSource1: TDataSource
    DataSet = ClientDataSet1
    Left = 448
    Top = 16
  end
  object DataSource2: TDataSource
    DataSet = ClientDataSet2
    Left = 544
    Top = 16
  end
  object ClientDataSet1: TClientDataSet
    Aggregates = <>
    Params = <>
    Left = 408
    Top = 16
  end
  object ClientDataSet2: TClientDataSet
    Aggregates = <>
    MasterSource = DataSource1
    PacketRecords = 0
    Params = <>
    Left = 496
    Top = 16
  end
end
对象格式1:t格式1
左=195
Top=124
宽度=623
高度=303
标题='Form1'
颜色=clBtnFace
Font.Charset=默认字符集
Font.Color=clWindowText
字体高度=-11
Font.Name='MS Sans Serif'
Font.Style=[]
OldCreateOrder=False
PixelsPerInch=96
text高度=13
对象DBText1:TDBText
左=307
Top=56
宽度=65
高度=17
数据源=数据源1
结束
对象面板1:TPanel
左=307
Top=80
宽度=281
高度=161
标题='Panel1'
TabOrder=0
对象DBText2:TDBText
左=24
Top=64
宽度=65
高度=17
数据源=数据源2
结束
结束
对象备忘录1:TMemo
左=8
Top=16
宽度=281
高度=225
TabOrder=1
结束
对象btnFind:TButton
左=307
Top=16
宽度=75
高度=25
标题='Find'
TabOrder=2
OnClick=btnFindClick
结束
对象数据源1:TDataSource
DataSet=ClientDataSet1
左=448
Top=16
结束
对象数据源2:TDataSource
DataSet=ClientDataSet2
左=544
Top=16
结束
对象ClientDataSet1:TClientDataSet
聚合=
参数=
左=408
Top=16
结束
对象ClientDataSet2:TClientDataSet
聚合=
MasterSource=数据源1
PacketRecords=0
参数=
左=496
Top=16
结束
结束

@TLama,DataLinks是TDataLink的列表。VisualControl是布尔型的。但它是哪个控件?@TLama,非常好,有了TFieldDataLink,我可以访问“control”属性,但有了tgridatalink.FGrid是私有成员:(如果没有人会给出更好的答案(包括TDBGrids)我会接受你的评论。@TLama,我错过了。请作为答案发布,我很乐意接受!抱歉,从这里收回我的所有评论…使用
数据链接
,没有可靠的方法访问所有类型链接控件的实例。我能想到的唯一剩下的方法是迭代所有控件并询问它们的
DataSource
属性。@MartynA,不幸的是不是…@TLama:哦,好吧。OP不能通过查找组件的DataSource和MasterSource属性,使用旧式RTTI来完成吗?您可以安全地编写
Result:=(IsPublishedProp(一个组件,'DataSource')和PropType(一个组件,'DataSource',tkClass)和(GetObjectProp)(一个组件,'DataSource',TDataSource)=ADataSource)或…
。我多么喜欢老式的RTTI:)@TLama:谢谢。我以前的版本会为没有DataSource/MasterSource的组件生成异常,这一直困扰着我,而且在一个项目中可能会有数百个异常。我以一种避免这种情况的方式重新编写了HasDataSource函数,而每个属性名只涉及一次属性信息访问。这是一种妄想c方法还将检查属性是否持有一个对象(
if PInfo^.PropType^.Kind=tkClass
),如果是,则检查您获得的对象是否真的属于类型
TDataSource
(寻址类型转换)。如果有人会进行(邪恶:-)如果组件发布了
DataSource
类型的属性,例如
Integer
,或者对象类与
TDataSource
不同,则函数将失败。[+1e因为RTTI是正确的方法,所以函数已经失效]