Delphi的一大亮点是TActionlist。更好的是像TDataset操作这样的默认TA操作。我有一张表格,里面有几张简单的桌子。因此,我让Delphi通过几个TDatasetinsert/delete/edit等来决定哪个数据源/表是活动的。
但现在我希望删除操作有一个对话框"你确定吗"之类的。如果我干预了操作的execute事件,则该操作似乎在对话框之后停止。所以我想像somedatasource.dataset.delete一样自己做删除操作。但我不知道哪个数据源对这个TDatasetdelete是活动的。
TDatasetdelete有一个数据源属性,但它默认为nil,读取它会导致访问冲突。即使我不分配它,当TDatasetdelete执行时,也会从我的一个数据源中删除一个数据行。在这种情况下,我如何找出哪个数据源是"活动的",换句话说,它在执行时将使用哪个数据源。
更新:我想我现在已经知道你在问什么了,那就是即使你没有分配DataSetDelete操作的DataSourceaction设法"知道"要对哪个数据源进行操作?
如果您的任何数据源都连接到TDBGrid,则对此有一个解释或其数据链路包含类似于以下代码的任何其他DB感知组件:
function TCustomDBGrid.UpdateAction(Action: TBasicAction): Boolean;
begin
Result := (DataLink <> nil) and DataLink.UpdateAction(Action);
end;
如果在Result := ...
上放置断点,您会发现它被调用在应用程序运行时重复。
现在用我下面的代码试试这个:
断开两个DBGrids与其重复数据源的连接,然后编译并运行:
结果:DataSetDelete菜单项被禁用(!)。
接下来,将DBGrid2连接到DataSource2。编译并运行。
结果:DataSetDelete菜单项已启用,单击它将删除来自CDS2的当前行。
接下来,将DBGrid1连接到DataSource1。编译并运行。
结果:DataSetDelete菜单项已启用,单击它将从CDS1中删除当前行。
正如您所看到的,除非您的代码显式设置DataSetAction的DataSource属性,此操作对第一个数据链路的数据源进行操作从DB感知组件的UpdateAction
函数返回True。
换句话说,与其说DataSetDelete操作"知道"如果未分配DataSetDelete操作的datasource属性,而是使用DB感知组件的数据链接告诉哪个数据源处于活动状态。
Update2要理解我的意思,请删除您目前拥有的DataSetDelete的OnExecute的任何处理程序。然后,在DBActns.Pas中的TDataSetDelete.ExecuteTarget
上放置一个断点。当它跳闸时,查看调用堆栈,你会发现它是从TCustomDBGrid.ExecuteAction调用的,所以数据集的标识被传递给DataSetDelete操作,所以我认为没有办法从DataSetDelease操作本身找到数据集的身份。
然而,有一个简单的方法可以解决这个问题。将以下BeforeDelete处理程序附加到每个数据集:
procedure TCDSForm.CDS1BeforeDelete(DataSet: TDataSet);
begin
if MessageDlg(DataSet.Name + ': Delete record?', mtConfirmation, [mbYes, mbNo], 0) <> mrYes then
Abort;
end;
然后,无论您是否尝试删除数据集记录,无论是否使用DataSetDelete操作,都会调用此事件处理程序,如果用户没有响应"是",则会调用Abort过程,从而引发一个静默异常,阻止删除继续进行。
===============
原答覆如下。我稍后会整理
如果我理解正确的话,下面的示例项目应该能满足你的需求。
我的问题是:如何读取活动数据源组件名
答案是TDataSetDelete操作具有DataSource属性这只是一个设置您想要激活的数据源的问题。
"Delphi知道什么数据源是活动的"否,当然它不知道,除非你告诉它你希望DataSetDelete操作在什么数据源上,否则它怎么可能?这样做的方法是设置其DataSource
属性。按照我的意思,编译下面的代码,在上设置一个断点
Caption := 'Execute'
在DataSetDelete1Execute
内部;运行该项目,然后单击DataSetDelete1Execute菜单项。断点跳闸时,评估`TDataSetDelete(Sender).DataSource.您会发现该值为Nil,因为您还没有告诉操作要操作的数据源。
然后,取消注释行
SetDataSource(DataSource1);
在CCD_ 6中并重复评估。现在,操作知道,因为您已经告诉它,它应该考虑哪个数据源是活动的。
如果你第一次错过了,那就是
DatasetDelete1.DataSource := FDataSource;
在CCD_ 7中设置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;