Update: Я думаю, теперь я знаю, понимаю, что вы на самом деле просите, что в том, что даже если вы оставите DataSource в действии DataSetDelete в неактивны, как это, что действия удается каким-то образом «знать», что источник данных для действовать?
Существует объяснение для этого, если какие-либо из ваших источников данных подключены к TDBGrids или любой другой БД осведомленном компоненте, DATALINK содержит код, подобный следующему:
function TCustomDBGrid.UpdateAction(Action: TBasicAction): Boolean;
begin
Result := (DataLink <> nil) and DataLink.UpdateAction(Action);
end;
Если поставить точку останова на Result := ...
вы обнаружите, что он многократно называет , когда приложение запущено.
Теперь попробуйте это с моим кодом ниже:
Отсоедините два DBGrids от их repective источника данных, а затем скомпилировать и запустить:
Результат: (!) Пункт меню DataSetDelete отключен.
Далее подключите DBGrid2 к DataSource2. Скомпилируйте и запустите.
Результат: Пункт меню DataSetDelete включен и щелчок по нему удаляет текущую строку с CDS2.
Далее подключите DBGrid1 к DataSource1. Скомпилируйте и запустите.
Результат: Пункт меню DataSetDelete является включен и щелкнув по нему удаляет текущую строку из CDS1.
Как вы можете видеть, если ваш код в явном виде Устанавливает DataSetAction в свойство DataSource , эта акция действует на источнике данных первого Datalink который возвращает значение ИСТИНЫ из UpdateAction
функции БД-Aware компоненты.
Другими словами, это не так много, что действие DataSetDelete «знает», что DataSource использовать, если вы оставите DataSource собственность DataSetDelete действия пользователя неактивны, а то, что DATALINKS БД-Aware компоненты, которые сказать о действие, в котором активен источник данных.
Обновление 2 Чтобы видеть, что я имею в виду, удалите любой обработчик, который у вас есть на данный момент для OnExecute DataSetDelete. Затем положите точку останова на TDataSetDelete.ExecuteTarget
в DBActns.Pas. Когда он отключается, посмотрите на стек вызовов, и вы обнаружите, что он вызывается из 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 или нет, этот обработчик события будет вызван, и если пользователь Безразлично» t ответьте «Да», вызывается процедура «Прерывание», создавая исключение без звука, которое предотвращает удаление.
==============
Оригинальный ответ следующим образом. Я приведу его позже.
Если я правильно понимаю вас, пример проекта ниже должен делать то, что вы хотите.
Мой вопрос: как я могу прочитать активный источник данных-ComponentName
Ответ на этот вопрос является то, что действие TDataSetDelete имеет свойство DataSource и это просто вопрос о создании, к которой DataSource вы хотите будет активным.
«Delphi знает, что источник данных не активен» Нет, конечно, это не делает, как это могло возможно, пока вы сказать ему, что DataSource вы хотите действие DataSetDelete работать на? И как вы это делаете, установите его свойство DataSource
. Для того, чтобы следовать тому, что я имею в виду, компилировать код, приведенный ниже, установите точку останова на
Caption := 'Execute'
внутри DataSetDelete1Execute
, затем скомпилировать & запустить проект и выберите пункт меню DataSetDelete1Execute. Когда точка останова отключится, оцените `TDataSetDelete (Sender) .DataSource. Вы найдете значение Nil, потому что вы не сказали (а) о действии, которому источник данных должен действовать.
Затем раскомментировать строку
SetDataSource(DataSource1);
в FormCreate
и повторить оценку. Теперь действие знает, потому что вы сказали ему, какой источник данных он должен считать активным.
В случае, если вы пропустили его в первый раз, это линия
DatasetDelete1.DataSource := FDataSource;
в procedure TCDSForm.SetDataSource(const Value: TDataSource)
, который устанавливает набор данных, который использует действие DatasetDelete1.
Btw, нет "волшебной" любой из этого - посмотрите на исходный код 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;
Прошу прощения, мы не можем видеть ваши creen или читать ваш ум. Предоставьте дополнительную информацию о том, как работает ваше приложение. На данный момент я не могу делать головы или хвосты из того, что делает ваше приложение. –
Извините. но для программистов-дельфи я подумал, что TDatasetdelete, который является TAction по умолчанию, прекратил свое существование. Извини за это. – user3415259
@KenWhite: На самом деле (и, к моему большому удивлению), OP, похоже, имеет смысл - пожалуйста, ознакомьтесь с обновлением моего ответа. – MartynA