【问题标题】:How to detect user either in DBGrid or ClientDataset has deleted data in a cell at runtime?如何检测 DBGrid 或 ClientDataset 中的用户在运行时删除了单元格中的数据?
【发布时间】:2021-04-18 13:26:05
【问题描述】:

我有一个程序需要由用户删除单元格中的数据来触发/触发。看起来 ClientDataset.Delete 不适合这种情况。

我的数据结构是:

TADOConnection -> TADOQuery -> TDataSetProvider -> TClientDataSet -> TDataSource -> TDBGRidEh (descendant of TDBGrid)

我是否需要创建一个过程来检测删除,或者是否已经有一个事件或属性可以用于此目的?

【问题讨论】:

  • 您是指删除完整记录还是删除字段值(也就是将其设置为空)? TDataset 具有 OnBeforeDelete 和 OnAfterDelete 事件,用于在删除记录之前/之后采取行动。 TDataSource 有一个 OnDataChange 事件来检测字段级别的数据更改(也就是允许您采取行动) - 注意:当用户移动到另一条记录时,也会触发最后一个事件,因此当数据更改时,您应该检查连接的 TDataset 的状态。
  • @R.Hoek 我指的是删除字段值,而不是完整的记录。我已经尝试过 OnBefore/AfterDelete 但没有成功——它甚至在运行时都没有被触及。我不确定 ClientDataSet.Delete 是否在每条记录/行的基础上完成它的工作。但至于 TDataSource 事件,我现在必须研究它。有 3 个事件 OnDataChange、OnSateChange 和 OnUpdateData。我会就此与您联系。

标签: delphi event-handling tclientdataset dbgrid


【解决方案1】:

下面的代码应该检测到您的 CDS 的给定字段(在此示例中为 Customer)何时被修改,因此 其 AsString 属性为空字符串或字段的值已 设置为 Null,但在任何一种情况下,仅当该字段之前具有非 Null、非空值时。

它使用 TFieldDataLink 的自定义后代来进行检测和处理 dsFieldChange 事件。这只会在 Post 方法正在执行且尚未返回时立即触发。

type
  TMyFieldDataLink = class(TFieldDataLink)
    procedure DataEvent(Event: TDataEvent; Info: Integer); override;
  end;

type
  TForm1 = class(TForm)
    ClientDataSet1: TClientDataSet;
    DataSource1: TDataSource;
    DBGrid1: TDBGrid;
    ADOConnection1: TADOConnection;
    ADOQuery1: TADOQuery;
    DataSetProvider1: TDataSetProvider;
    DBNavigator1: TDBNavigator;
    DBEdit1: TDBEdit;
    procedure FormCreate(Sender: TObject);
  private
    FieldDataLink : TFieldDataLink;
  end;
[...]
procedure TForm1.FormCreate(Sender: TObject);
begin
  FieldDataLink := TMyFieldDataLink.Create;
  FieldDataLink.DataSource := DataSource1;
  FieldDataLink.FieldName := 'Company';
end;

{ TMyFieldDataLink }

procedure TMyFieldDataLink.DataEvent(Event: TDataEvent; Info: Integer);
var
  S : String;
  V : Variant;
begin
  inherited;

  if Event = deFieldChange then begin
    V :=  Field.OldValue;
    if not VarIsNull(V) then begin
      S := V;
      if (S <> '') and (Field <> Nil) and (Field.IsNull or (Field.AsString = '')) then begin
        ShowMessage('Field: ' + Field.FieldName + ' emptied');
      end;
    end;
  end;
end;

要使用、剪切并粘贴到新的 VCL 项目中。

顺便说一句,对于这样的问题,最好从数据集的角度而不是从 DBGrid 等特定组件的角度开始。

【讨论】:

  • 一如既往,你的回答让我吃惊!我这里有小问题。当我运行它失败时,会弹出此错误消息[dcc32 Error] main_u.pas(13): E2037 Declaration of 'DataEvent' differs from previous declaration。我不确定这是否与版本有关。我正在使用社区版还是错过了什么?
  • 完全不用担心!请忽略我的小问题。我从 TFieldDataLink 声明中找到了它。我将 Info: Integer 更改为 NativeInt -> procedure DataEvent(Event: TDataEvent; Info: NativeInt); override; 现在它可以工作了!
  • 非常感谢!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-03-15
  • 2021-07-06
  • 2011-01-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-24
相关资源
最近更新 更多