更新:あなたが実際に求めていることを理解できたと思います.DataSetDelete アクションの DataSource を割り当てられていないままにしても、どのデータソースを操作するかをアクションがどうにかして「知る」ことはできますか?
データソースのいずれかが TDBGrids またはデータリンクに次のようなコードが含まれるその他の DB 対応コンポーネントに接続されている場合、これについて説明があります。
function TCustomDBGrid.UpdateAction(Action: TBasicAction): Boolean;
begin
Result := (DataLink <> nil) and DataLink.UpdateAction(Action);
end;
にブレークポイントを配置するResult := ...
と、アプリの実行中に繰り返し呼び出されることがわかります。
以下の私のコードでこれを試してください:
2 つの DBGrid をそれぞれのデータソースから切断し、コンパイルして実行します。
結果: DataSetDelete メニュー項目が無効になります (!)。
次に、DBGrid2 を DataSource2 に接続します。コンパイルして実行します。
結果: DataSetDelete メニュー項目が有効になり、クリックすると現在の行が CDS2 から削除されます。
次に、DBGrid1 を DataSource1 に接続します。コンパイルして実行します。
結果: DataSetDelete メニュー項目が有効になり、クリックすると現在の行がCDS1から削除されます。
ご覧のとおり、コードで DataSetAction の DataSource プロパティを明示的にUpdateAction
設定しない限り、このアクションは、DB 対応コンポーネントの関数から True を返す最初のデータリンクのデータソースで動作します。
つまり、DataSetDelete アクションの DataSource プロパティを割り当てないままにしておくと、DataSetDelete アクションがどのデータソースを使用するかを「認識」するというよりも、
どのデータソースがアクティブであるかをアクションに伝えるDB 対応コンポーネントのデータリンクを認識します。
更新 2 私が何を意味するかを確認するには、DataSetDelete の OnExecute に対して現在持っているハンドラーをすべて削除します。次に、TDataSetDelete.ExecuteTarget
DBActns.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;