parent dla jakiejś formy może być różny, więc procedura sprawdzenia wybranego w child'zdie rekordu też może być inna tak samo jak inne możne być podpowiadanie
bardziej obrazkowy opis:
mamy formę bazową "podłoga" i dzieci "płytki" & "panele"
jeśli zaznaczę jakiś rekord na formie "podłoga", przejdę do "płytki", to zobaczę powiązane z tą podłogą płytki - przekaże rekord z min. customową procedurą onshow, która np. ukryje mi pola widoczne gry parentem jest "ściana", a pokaże te dla "podłoga"
OK, ale dalej nie rozumiem po co chcesz przekazywać rekord z formy podłoga
do formy płytki
?
Dlaczego nie miałbyś przekazać PK z podłogi do płytek, a sama "forma" płytki nie pobierze sobie odpowiednich danych na podstawie przekazanego PK?
jak będę chciał dodać nową "płytkę" lub "panel", to z przekazanego rekordu "podłoga" mogę podpowiedzieć jakieś dane przekazując customową "onNewRecord"
Jak wyżej - po co rekord?
co do lookupów - owszem, zostaną, ale dzięki rozbudowanemu kontekstowi nie muszę z jednej formy sięgać do innej formy
Nigdy nie powinieneś sięgać z jednej formy do innej formy wprost, czyli odwołując się np. tak:
jakasDana := formaParent.DS1.FieldByName('Pole1').Value;
Jeśli cokolwiek zmienisz na jakiejkolwiek formie, to ten mechanizm może przestać działać poprawnie.
Ale gdybyś zrobił to np. tak, czyli za pomocą dedykowanego interfejsu przekazującego dane pomiędzy formami:
type
IDSCRecord = interface
['{ABD0C10D-459E-414F-8DA9-ADF1ECEFDAD9}']
/// <summary>Tablica zawierająca wartości PK, którymi to wartościami należy odświeżyć RootDS DSControllera</summary>
property KeyValues: Variant read GetKeyValues write SetKeyValues;
property LookupName: string read GetLookupName write SetLookupName;
/// <summary>Typ akcji, po której ma zostać wykonane odświeżenie rekordu</summary>
property NotifyDBType: TDSCAction read GetNotifyDBType write SetNotifyDBType;
/// <summary>Referencja na dataset z które pochodzi rekord</summary>
property ReferenceDS: TADAdaptedDataSet read GetReferenceDS write SetReferenceDS;
property ReferenceField: TField read GetReferenceField write SetReferenceField;
end;
A sama implementacja może wyglądać np. tak:
type
TFormBase = class(TForm)
protected
procedure ConsumeInitData(AInitData : IInterface); virtual; abstract;
public
constructor Create(AOwner : TComponent; AInitData : IInterface = nil);
end;
implementation
TFormBase.Create(AOwner : TComponent; AInitData : IInterface = nil);
begin
inherited Create(AOwner);
ConsumeInitData(AInitData);
end;
Potem dla każdej formy, która dziedziczy z TFormBase
musisz dostarczyć implementację metody abstrakcyjnej ConsumeInitData
, czyli np. tak:
type
TFormBase = class(TForm)
protected
procedure ConsumeInitData(AInitData : IInterface); override;
end;
implementation
TFormBase.ConsumeInitData(AInitData : IInterface);
var
lDSCRecord : IDSCRecord;
begin
if Supports(AInitData, IDSCRecord, lDSCRecord) then
begin
// openData to jakaś metoda, która otwiera źródła danych na podstawie PK.
OpenData(lDSCRecord.KeyValues);
end;
end;
W ten sposób masz to wszystko rozdzielone, możesz to zrobić inaczej - czyli całkowicie odseparować zarządzanie danymi od formatek (i ja mam to tak zrobione), możesz delegować odpowiednie procesy (np. otwieranie danych, sprawdzanie danych, modyfikację kontrolek, itd.) do specjalizowanego kodu.
Zgoda - jest z tym więcej zachodu na początku, ale im dalej w las z rozwojem programu, tym łatwiej się tym zarządza, rozwija i panuje.
Nie mieszaj wszystkiego ze wszystkim - czyli kodu odpowiedzialnego za otwierani danych w metodzie OnShow. W ten sposób silnie wiążesz jakąś funkcjonalność z konkretną instancją klasy - a to jest mocno niefajne.
Ja używam tego samego interfejsu (IDSCRecord
) zarówno do przekazywania danych startowych jak i do zapewnienia notyfikacji dla obiektów powiązanych (np. forma lista i szczegóły; jeśli coś zmienię na formie szczegóły to lista musi się odświeżyć, a dzięki powiązaniu wie dokładnie co ma odświeżyć i kiedy).