0

Delphi の素晴らしい点の 1 つは、TActionlist です。さらに良いのは、TDataset-actions のようなデフォルトの TActions です。いくつかの単純なテーブルを含む 1 つのフォームがあります。そこで、Delphi に、いくつかの TDatasetinsert/delete/edit などを使用してアクティブなデータソース/テーブルを決定させます。

しかし今、私は「よろしいですか」などのダイアログボックスを持つ削除アクションが必要です。アクションの実行イベントに干渉すると、ダイアログの後にアクションが停止したように見えます。だから私はsomedatasource.dataset.deleteのように自分で削除アクションをしたい. しかし、この TDatasetdelete でアクティブになっているデータソースがわかりません。

TDatasetdelete には datasource プロパティがありますが、これはデフォルトで nil に設定されており、これを読み取るとアクセス違反が発生します。未割り当てのままにしても、TDatasetdelete を実行すると、データ ソースの 1 つからデータ行が削除されます。このような状況では、どのデータソースが「アクティブ」であるか、つまり、実行時にどのデータソースが使用されるかを確認するにはどうすればよいでしょうか。

4

1 に答える 1

4

更新:あなたが実際に求めていることを理解できたと思います.DataSetDelete アクションの DataSource を割り当てられていないままにしても、どのデータソースを操作するかをアクションがどうにかして「知る」ことはできますか?

データソースのいずれかが TDBGrids またはデータリンクに次のようなコードが含まれるその他の DB 対応コンポーネントに接続されている場合、これについて説明があります。

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

にブレークポイントを配置するResult := ...と、アプリの実行中に繰り返し呼び出されることがわかります。

以下の私のコードでこれを試してください:

  1. 2 つの DBGrid をそれぞれのデータソースから切断し、コンパイルして実行します。

    結果: DataSetDelete メニュー項目が無効になります (!)。

  2. 次に、DBGrid2 を DataSource2 に接続します。コンパイルして実行します。

    結果: DataSetDelete メニュー項目が有効になり、クリックすると現在の行が CDS2 から削除されます。

  3. 次に、DBGrid1 を DataSource1 に接続します。コンパイルして実行します。

    結果: DataSetDelete メニュー項目が有効になり、クリックすると現在の行がCDS1から削除されます。

ご覧のとおり、コードで DataSetAction の DataSource プロパティを明示的にUpdateAction設定しない限り、このアクションは、DB 対応コンポーネントの関数から True を返す最初のデータリンクのデータソースで動作します。

つまり、DataSetDelete アクションの DataSource プロパティを割り当てないままにしておくと、DataSetDelete アクションがどのデータソースを使用するかを「認識」するというよりも、 どのデータソースがアクティブであるかをアクションに伝えるDB 対応コンポーネントのデータリンクを認識します。

更新 2 私が何を意味するかを確認するには、DataSetDelete の OnExecute に対して現在持っているハンドラーをすべて削除します。次に、TDataSetDelete.ExecuteTargetDBActns.Pas にブレークポイントを設定します。トリップしたらコールスタックを見ると、TCustomDBGrid.ExecuteActionから呼び出されていることがわかりますので、データセットのIDをDataSetDeleteアクションに渡しているので、調べる方法は無いと思いますDataSetDelete アクション自体からのデータセットの ID。

ただし、これを回避する簡単な方法があります。次の BeforeDelete ハンドラーを各データセットにアタッチします。

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

次に、データセット レコードを削除しようとするかどうかにかかわらず、DataSetDelete アクションを使用するかどうかにかかわらず、このイベント ハンドラーが呼び出されます。ユーザーが "はい" と応答しない場合は、Abort プロシージャが呼び出され、サイレント例外が発生します。続行からの削除。

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

元の答えは次のとおりです。後で整理します

私があなたを正しく理解しているなら、以下のサンプルプロジェクトはあなたが望むことをするはずです。

私の質問は、アクティブな datasource-componentname をどのように読み取ることができるかです。

これに対する答えは、TDataSetDelete アクションには DataSource プロパティがあり、アクティブにしたいデータソースを設定するだけの問題です。

「Delphi はアクティブなデータソースを認識しています」 いいえもちろんそうではありません。その方法は、そのプロパティを設定することです。私の言いたいことに従うには、以下のコードをコンパイルし、ブレークポイントを設定しますDataSource

Caption := 'Execute'

内部DataSetDelete1Executeで、プロジェクトをコンパイルして実行し、DataSetDelete1Execute メニュー項目をクリックします。ブレークポイントがトリップしたら、`TDataSetDelete(Sender).DataSource. アクションが操作するデータソースを (まだ) アクションに伝えていないため、値はNilであることがわかります。

次に、行のコメントを外します

SetDataSource(DataSource1);

評価をFormCreate繰り返します。これで、アクションは、どのデータソースがアクティブであると見なす必要があるかを通知したため、認識されます。

初めて見逃した場合は、ラインです

  DatasetDelete1.DataSource := FDataSource;

procedure TCDSForm.SetDataSource(const Value: TDataSource)DatasetDelete1 アクションが使用するデータセットを設定します。

ところで、これには「魔法」はありません-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;
于 2016-07-30T17:30:55.723 に答える