2016-07-30 5 views
0

Одна из замечательных вещей в Delphi - список TActionlist. Еще лучше - такие TActions, как TDataset-действия. У меня есть одна форма с несколькими простыми таблицами. Поэтому я разрешаю Delphi решать, какой источник данных/таблица активен с несколькими TDatasetinsert/delete/edit и т. Д.Delphi default dataset action Tdatasetdelete

Но теперь я хочу, чтобы действие удаления имело диалоговое окно «Вы уверены» или что-то в этом роде. Если я вмешиваюсь в событие выполнения действия, действие, похоже, останавливается после диалога. Поэтому я хочу выполнить действие delete как somedatasource.dataset.delete. Но я не могу понять, какой источник данных активен для этого TDatasetdelete.

TDatasetdelete имеет свойство datasource, но это значение по умолчанию равно нулю, и чтение его дает нарушение доступа. Даже если я оставлю его неназначенным, строка данных удаляется из одного из моих источников данных, когда TDatasetdelete выполняется. В этих обстоятельствах, как узнать, какой источник данных является «активным», другими словами, какой источник данных он будет использовать, когда он будет выполняться.

+0

Прошу прощения, мы не можем видеть ваши creen или читать ваш ум. Предоставьте дополнительную информацию о том, как работает ваше приложение. На данный момент я не могу делать головы или хвосты из того, что делает ваше приложение. –

+0

Извините. но для программистов-дельфи я подумал, что TDatasetdelete, который является TAction по умолчанию, прекратил свое существование. Извини за это. – user3415259

+1

@KenWhite: На самом деле (и, к моему большому удивлению), OP, похоже, имеет смысл - пожалуйста, ознакомьтесь с обновлением моего ответа. – MartynA

ответ

4

Update: Я думаю, теперь я знаю, понимаю, что вы на самом деле просите, что в том, что даже если вы оставите DataSource в действии DataSetDelete в неактивны, как это, что действия удается каким-то образом «знать», что источник данных для действовать?

Существует объяснение для этого, если какие-либо из ваших источников данных подключены к TDBGrids или любой другой БД осведомленном компоненте, DATALINK содержит код, подобный следующему:

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

Если поставить точку останова на Result := ... вы обнаружите, что он многократно называет , когда приложение запущено.

Теперь попробуйте это с моим кодом ниже:

  1. Отсоедините два DBGrids от их repective источника данных, а затем скомпилировать и запустить:

    Результат: (!) Пункт меню DataSetDelete отключен.

  2. Далее подключите DBGrid2 к DataSource2. Скомпилируйте и запустите.

    Результат: Пункт меню DataSetDelete включен и щелчок по нему удаляет текущую строку с CDS2.

  3. Далее подключите 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; 
+0

Силой этого Tdatasetdelete является то, что если у вас есть несколько источников данных, которые могут быть связаны с этим действием, Delphi знает, какой источник данных активен. Таким образом, имея одну кнопку удаления с одним TDatasetdelete TAction и дюжиной tdatasets, источник данных устанавливается динамически во время выполнения. Мой вопрос: как я могу прочитать активный datasource-componentname – user3415259

+0

@ user3415259 Я понятия не имею, почему вы все еще думаете, что у Delphi есть своего рода волшебный читатель разума, который может определить, какой набор данных «активен». Это не имеет понятия. Это зависит от вас. Delphi - это язык, который ожидает, что вы обратите пристальное внимание на детали и напишите код или внесите соответствующие изменения по мере необходимости. Некоторые задачи даже требуют от вас переопределения Delphi RTL или VCL и т. Д., Чтобы выполнить то, что вы хотите. Это всего лишь рамка, а не искусственный интеллект. –

+0

Mindreader - это ваши слова. Попробуйте, вы увидите, что Delphi знает, какой компонент активен, и подключает источник данных этого компонента к TDatasetaction во время выполнения. Так что это очень удобно использовать для разработчика. Примите, если он хочет какое-то взаимодействие, как в моем случае. Источник данных равен нулю, если я хочу его использовать. Поэтому мой вопрос по-прежнему: есть ли возможность (за исключением написания моего собственного кода, чтобы это сделать), чтобы узнать, какой источник данных активен. Если я полностью ошибаюсь, я бы оценил некоторую ясность в отношении этого TAction. – user3415259

Смежные вопросы