Delphi默认数据集操作Tdatasetdelete

时间:2016-07-30 16:55:35

标签: delphi taction tactionlist

Delphi的一个奇妙之处是TActionlist。更好的是像TDataset-actions这样的默认TATION。我有一个表格有几个简单的表格。所以我让Delphi通过几个TDatasetinsert / delete / edit等来决定哪个数据源/表是活动的。

但现在我希望删除操作有一个对话框"你确定"或者其他的东西。如果我干扰操作的执行事件,则操作似乎在对话框后停止。所以我想像somedatasource.dataset.delete一样自己做删除操作。但我无法确定哪个数据源对此TDatasetdelete有效。

TDatasetdelete具有数据源属性,但默认为nil并且读取它会导致访问冲突。即使我将其保留为未分配状态,当执行TDatasetdelete时,也会从我的一个数据源中删除数据行。在这种情况下,我如何找出哪个数据源是"活动",换句话说,它将在执行时使用哪个数据源。

1 个答案:

答案 0 :(得分:4)

更新:我想我现在知道了解你的实际问题,即使你将DataSetDelete操作的数据源保留为未分配状态,它是怎么回事? 行动以某种方式管理"知道"哪个数据源可以运行?

如果您的任何数据源连接到TDBGrids,则会对此进行解释 或任何其他DB-aware组件,其数据链接包含类似于以下内容的代码:

function TCustomDBGrid.UpdateAction(Action: TBasicAction): Boolean;
begin
  Result := (DataLink <> nil) and DataLink.UpdateAction(Action);
end;

如果在Result := ...上放置一个断点,你会发现它被调用了 在应用程序运行时反复出现。

现在尝试使用我的代码:

  1. 断开两个DBGrids的数据源,然后编译并运行:

    结果:DataSetDelete菜单项被禁用(!)。

  2. 接下来将DBGrid2连接到DataSource2。编译并运行。

    结果:DataSetDelete菜单项启用并单击它会删除 来自CDS2的当前行。

  3. 接下来将DBGrid1连接到DataSource1。编译并运行。

    结果:DataSetDelete菜单项启用,点击它会从 CDS1 中删除当前行。

  4. 如您所见,除非您的代码显式设置DataSetAction的数据源 属性,此操作在第一个数据链路的数据源上运行 从数据库感知组件的UpdateAction函数返回True。

    换句话说,DataSetDelete操作&#34;知道&#34;并非如此。哪一个 如果您将DataSetDelete操作的DataSource属性保留为未分配,则使用的数据源,而不是DB-aware组件&#39; datalinks 告诉数据源处于活动状态的操作。

    更新2 要查看我的意思,请删除您目前为DataSetDelete的OnExecute提供的所有处理程序。然后,在DBActns.Pas中的TDataSetDelete.ExecuteTarget上放置一个断点。当它跳闸时,查看调用堆栈,你会发现它是从TCustomDBGrid.ExecuteAction调用的,所以数据集的标识正被传递给DataSetDelete动作,所以我认为没有办法从DataSetDelete操作本身中找出数据集的标识。

    然而,有一个简单的方法。将以下BeforeDelete处理程序附加到每个数据集:

    procedure TCDSForm.CDS1BeforeDelete(DataSet: TDataSet);
    begin
      if MessageDlg(DataSet.Name + ': Delete record?', mtConfirmation, [mbYes, mbNo], 0) <>  mrYes then
        Abort;
    end;
    

    然后,无论您是否尝试删除数据集记录,无论是否使用DataSetDelete操作,都将调用此事件处理程序,如果用户没有响应&#34;是&#34;,则中止调用过程,引发一个静默异常,阻止删除进行。

    ==============

    原始答案如下。我稍后会把它整理好

    如果我正确理解你,下面的示例项目应该做你想要的。

    我的问题是:如何读取活动数据源组件名

    答案是TDataSetDelete操作具有DataSource属性 并且只是设置您想要激活哪个数据源的问题

    &#34; Delphi知道什么数据源是活跃的&#34; ,当然它没有,在你告诉它想要DataSetDelete操作操作的数据源之前怎么可能呢?你这样做的方法是设置它的DataSource属性。按照我的意思,编译下面的代码,在

    上设置断点
    Caption := 'Execute'
    

    DataSetDelete1Execute内,然后编译&amp;运行该项目并单击DataSetDelete1Execute菜单项。当断点跳闸时,评估 `TDataSetDelete(发件人).DataSource。您会发现值 Nil ,因为尚未告知操作操作的数据源操作。

    然后,取消注释该行

    SetDataSource(DataSource1);
    
    FormCreate

    并重复评估。现在行动知道,因为您已经告诉它,它应该认为哪个数据源是活跃的。

    如果您第一次错过了它,那就是

      DatasetDelete1.DataSource := FDataSource;
    
    procedure TCDSForm.SetDataSource(const Value: TDataSource)中的

    ,用于设置DatasetDelete1操作使用的数据集。

    是的,没有&#34;魔法&#34;任何这一点 - 看看Delphi的源代码

    function TDataSetAction.GetDataSet(Target: TObject): TDataSet;
    begin
      { We could cast Target as a TDataSource since HandlesTarget "should" be
        called before ExecuteTarget and UpdateTarget, however, we're being safe. }
      Result := (Target as TDataSource).DataSet;
    end;
    

    procedure TDataSetDelete.ExecuteTarget(Target: TObject);
    begin
      GetDataSet(Target).Delete;
    end;
    

    代码(更新):

    unit cdsActionListu;
    
    interface
    
    uses
      Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
      Grids, DBGrids, DB, DBClient, StdCtrls, ExtCtrls, DBCtrls, ActnList,
      DBActns, Menus;
    
    type
    
      TCDSForm = class(TForm)
        CDS1: TClientDataSet;
        DataSource1: TDataSource;
        DBGrid1: TDBGrid;
        DBNavigator1: TDBNavigator;
        DBGrid2: TDBGrid;
        CDS2: TClientDataSet;
        DataSource2: TDataSource;
        DBNavigator2: TDBNavigator;
        ActionList1: TActionList;
        DataSetDelete1: TDataSetDelete;
        MainMenu1: TMainMenu;
        actSelectDataSource: TAction;
        ListBox1: TListBox;
        DataSetDelete11: TMenuItem;
        procedure DataSetDelete1Execute(Sender: TObject);
        procedure FormCreate(Sender: TObject);
        procedure ListBox1Click(Sender: TObject);
      private
        FDataSource: TDataSource;
        procedure SetDataSource(const Value: TDataSource);
      public
        property ActiveDataSource : TDataSource read FDataSource write SetDataSource;
      end;
    
    var
      CDSForm: TCDSForm;
    
    implementation
    
    {$R *.DFM}
    
    
    function CreateField(AFieldClass : TFieldClass; AOwner : TComponent; ADataSet : TDataSet;
    AFieldName, AName : String; ASize : Integer; AFieldKind : TFieldKind) : TField;
    begin
      Result := AFieldClass.Create(AOwner);
      Result.FieldKind := AFieldKind;
      Result.FieldName := AFieldName;
      Result.Name := AName;
      Result.Size := ASize;
      Result.DataSet := ADataSet;
    end;
    
    procedure TCDSForm.DataSetDelete1Execute(Sender: TObject);
    begin
      Caption := 'Execute';
      { uncomment the following to actually delete the record
          if MessageDlg('Delete record?', mtConfirmation, [mbYes, mbNo], 0) = mrYes then begin
              TDataSetDelete(Sender).DataSource.DataSet.Delete;
            end;
      }
    
    end;
    
    procedure TCDSForm.FormCreate(Sender: TObject);
    var
      Field : TField;
    begin
      Field := CreateField(TIntegerField, Self, CDS1, 'ID', 'CDS1ID', 0, fkData);
      Field := CreateField(TStringField, Self, CDS1, 'StringField', 'CDS1Stringfield', 40, fkData);
    
      CDS1.CreateDataSet;
      CDS1.InsertRecord([1, 'CDS1 Value1']);
      CDS1.InsertRecord([2, 'CDS1 Value2']);
    
      Field := CreateField(TIntegerField, Self, CDS2, 'ID', 'CDS2ID', 0, fkData);
      Field := CreateField(TStringField, Self, CDS2, 'StringField', 'CDS2Stringfield', 40, fkData);
    
      CDS2.CreateDataSet;
      CDS2.InsertRecord([1, 'CDS2 Value1']);
      CDS2.InsertRecord([2, 'CDS2 Value2']);
    
      Listbox1.Items.AddObject(Datasource1.Name, DataSource1);
      Listbox1.Items.AddObject(Datasource2.Name, DataSource2);
    
    //  SetDataSource(DataSource1);
    end;
    
    procedure TCDSForm.ListBox1Click(Sender: TObject);
    var
      Index : Integer;
    begin
      Index := Listbox1.ItemIndex;
      SetDataSource(TDataSource(Listbox1.Items.Objects[Index]));
    end;
    
    procedure TCDSForm.SetDataSource(const Value: TDataSource);
    var
      Index : Integer;
    begin
      FDataSource := Value;
      DatasetDelete1.DataSource := FDataSource;
      Index := ListBox1.Items.IndexOf(Value.Name);
      if Index <> ListBox1.ItemIndex then
        ListBox1.ItemIndex := Index;
      Caption := 'Active DS ' + FDataSource.Name;
    end;