2016-07-30 8 views
0

Eine der wunderbaren Dinge von Delphi ist eine TActionlist. Noch besser sind Standard-TActions wie TDataset-Aktionen. Ich habe ein Formular mit mehreren einfachen Tabellen. Also lasse ich Delphi entscheiden, welche Datenquelle/Tabelle aktiv ist mit mehreren TDataseinsert/delete/edit etc.Delphi Standard-Datenmenge Aktion Tdatasetdelete

Aber jetzt möchte ich die Löschaktion mit einem Dialogfeld "Bist du sicher" oder so etwas. Wenn ich beim Ausführen der Aktion eingreifen möchte, scheint die Aktion nach dem Dialog zu stoppen. Also möchte ich die Löschaktion selbst tun wie somedatasource.dataset.delete. Aber ich kann nicht herausfinden, welche Datenquelle für dieses TDatasetdelete aktiv ist.

Das TDatasetdelete verfügt über eine Datenquelleneigenschaft, die jedoch standardmäßig auf null eingestellt ist und beim Lesen eine Zugriffsverletzung ergibt. Auch wenn ich es nicht zugewiesen lasse, wird eine Datenzeile aus einer meiner Datenquellen gelöscht, wenn das TDatasetdelete ausgeführt wird. Unter diesen Umständen, wie finde ich heraus, welche Datenquelle "aktiv" ist, mit anderen Worten, welche Datenquelle verwendet wird, wenn sie ausgeführt wird.

+0

Es tut mir leid, wir können Ihre s nicht sehen riechen oder lesen Sie Ihre Gedanken. Bitte geben Sie weitere Informationen darüber an, wie Ihre Anwendung funktioniert. Ab sofort kann ich nicht ausrechnen, was Ihre Bewerbung tut. –

+0

Entschuldigung. aber für Delphi-Programmierer dachte ich, dass ein TDatasetdelete, das eine Standard-TAction ist, vertraut war. Das tut mir leid. – user3415259

+1

@KenWhite: Eigentlich (und sehr zu meiner Überraschung) scheint das OP einen Punkt zu haben - bitte sehen Sie das Update zu meiner Antwort. – MartynA

Antwort

4

Update: Ich glaube, ich weiß jetzt verstehen, was Sie fragen tatsächlich, was, dass selbst, wenn Sie die DataSetDelete Aktion der Datasource nicht zugewiesen lassen, wie es ist, dass die Aktion irgendwie schafft „wissen“, welche Datenquelle operieren?

Es gibt eine Erklärung dafür, ob alle Ihre Datenquellen TDBGrids verbunden sind oder einer anderen DB-Aware-Komponente, deren Datenlink enthält Code ähnlich der folgenden:

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

Wenn Sie einen Haltepunkt setzen auf die Result := ... Sie werden feststellen, dass es wiederholt aufgerufen wird, während die App ausgeführt wird.

Jetzt versucht dies mit meinem Code unten:

  1. trennen die beiden DBGrids von ihrer repective Datenquelle, dann kompilieren und ausführen:

    Ergebnis: (!) Der DataSetDelete Menüpunkt ist deaktiviert.

  2. Als nächstes verbinden Sie DBGrid2 mit DataSource2. Kompilieren und ausführen.

    Ergebnis: Der Menüeintrag DataSetDelete ist aktiviert und klicken Sie auf es löscht die aktuelle Zeile von CDS2.

  3. Als nächstes verbinden Sie DBGrid1 mit DataSource1. Kompilieren und ausführen.

    Ergebnis: Der DataSetDelete Menüpunkt ist aktiviert und Anklicken löscht die aktuelle Zeile aus CDS1.

Wie Sie sehen können, es sei denn, Ihr Code explizit der Datasource Eigenschaft DataSetAction setzt diese Aktion arbeitet auf der Datenquelle des ersten Datenverbindungs ​​die gibt Wahr zurück, von einem beliebigen DB-aware UpdateAction Funktion der Komponente.

Mit anderen Worten, es ist nicht so sehr, dass die DataSetDelete Aktion „weiß“, welche Datenquelle zu verwenden, wenn Sie die DataSetDelete Aktion der Datasource-Eigenschaft nicht zugewiesen verlassen, sondern vielmehr, dass die DB-Aware Komponenten Datenverbindungen, die sagen die Aktion welche Datenquelle aktiv ist.

Update 2 Um zu sehen, was ich meine, entfernen Sie alle derzeit verfügbaren Handler für OnExecute des DataSetDelete. Dann setzen Sie einen Breakpoint auf TDataSetDelete.ExecuteTarget in DBActns.Pas. Wenn der Fehler auftritt, sehen Sie sich den Aufruf-Stack an, und Sie werden feststellen, dass er von TCustomDBGrid.ExecuteAction aufgerufen wird, sodass die Identität des Datasets an die DataSetDelete-Aktion übergeben wird. Daher gibt es keine Möglichkeit, dies herauszufinden die Identität des Datasets von der DataSetDelete-Aktion selbst.

Es gibt jedoch einen einfachen Weg dazu. Bringen Sie die folgenden BeforeDelete-Handler für jede Ihrer Datensätze:

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

Dann ob Sie versuchen, einen Datensatz Datensatz zu löschen, ob die DataSetDelete Aktion mit oder nicht, wird dieser Event-Handler aufgerufen werden, und wenn der Benutzer doesn‘ Wenn Sie mit "Ja" antworten, wird die Abbruchprozedur aufgerufen, wodurch eine stumme Ausnahme ausgelöst wird, die verhindert, dass der Löschvorgang fortgesetzt wird.

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

Ursprüngliche Antwort folgt. Ich werde es später

aufzuräumen Wenn ich Sie richtig bin zu verstehen, das Beispielprojekt unten sollte das tun, was Sie wollen.

Meine Frage ist: Wie kann ich den aktiven Datenquelle-component lese

Die Antwort darauf ist, dass die TDataSetDelete Aktion eine Datasource-Eigenschaft hat und es ist nur eine Frage, die Datenquelle, auf die die Einstellung Sie wollen aktiv sein.

„Delphi weiß, welche Datenquelle ist aktiv“ Nein, natürlich ist es nicht, wie könnte es möglicherweise bis Sie es sagen, welche Datenquelle Sie die DataSetDelete Aktion wollen auf arbeiten? Und die Art, wie Sie das tun, ist seine Eigenschaft DataSource zu setzen. Zu folgen, was ich meine, kompilieren Sie den Code unten, einen Haltepunkt auf

Caption := 'Execute' 

innerhalb DataSetDelete1Execute, dann kompilieren & das Projekt ausführen und klicken Sie auf den Menüpunkt DataSetDelete1Execute. Wenn der Haltepunkt ausgelöst wird, evaluieren Sie `TDataSetDelete (Sender) .DataSource. Sie werden der Wert Nil finden, weil Sie haben (noch) nicht die Aktion gesagt, die Datenquelle die Wirkung auf den Betrieb ist.

Dann Kommentar- der Linie

SetDataSource(DataSource1); 

in FormCreate und die Auswertung wiederholen. Jetzt weiß die Aktion , weil Sie es gesagt haben, welche Datenquelle es als aktiv betrachten sollte.

Falls Sie es verpasst erstes Mal, es ist die Linie

DatasetDelete1.DataSource := FDataSource; 

in procedure TCDSForm.SetDataSource(const Value: TDataSource), die die Datenmenge, die die DatasetDelete1 Aktion verwendet setzt.

Btw, gibt es keine "Magie" zu einem dieser - Blick auf die Delphi-Quelle

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; 

und

procedure TDataSetDelete.ExecuteTarget(Target: TObject); 
begin 
    GetDataSet(Target).Delete; 
end; 

-Code (aktualisiert):

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

Die Stärke dieses Tdatasetdelete besteht darin, dass Delphi weiß, welche Datenquelle aktiv ist, wenn mehrere Datenquellen an diese Aktion gebunden sind. Mit einer Delete-Schaltfläche mit einer TDatasetdelete TAction und einem Dutzend Tdatasets wird die Datenquelle zur Laufzeit dynamisch gesetzt. Meine Frage ist: Wie kann ich den aktiven Datenquelle-Komponentenname lesen? – user3415259

+0

@ user3415259 Ich habe keine Ahnung, warum Sie immer noch denken, dass Delphi eine Art magischer Gedankenleser hat, der erkennen kann, welcher Datensatz "aktiv" ist. Es hat keine Ahnung. Es liegt an Ihnen zu implementieren. Delphi ist eine Sprache, die von Ihnen erwartet, dass Sie genau auf Details achten und Code schreiben oder bei Bedarf entsprechende Änderungen vornehmen. Bei einigen Aufgaben müssen Sie sogar Delphi RTL oder VCL usw. überschreiben, um das zu erreichen, was Sie wollen. Es ist nur ein Rahmen, keine künstliche Intelligenz. –

+0

Mindreader sind deine Worte. Probieren Sie es aus, Sie werden sehen, dass Delphi weiß, welche Komponente aktiv ist, und verbindet die Datenquelle dieser Komponente mit der TDatasetaction in Runtime. So ist es sehr praktisch für den Entwickler zu verwenden. Akzeptiere, wenn er eine Interaktion wünscht, wie in meinem Fall. Die Datenquelle ist Null, wenn ich sie benutzen möchte. Meine Frage ist also immer noch: Gibt es eine Möglichkeit, außer dass ich meinen eigenen Code schreibe, um zu sehen, welche Datenquelle aktiv ist? Wenn ich total falsch liege, würde ich einige Klarheit über diese TAction schätzen. – user3415259