Как я могу вернуть одно или несколько значений в мой метод события? - PullRequest
0 голосов
/ 26 августа 2009

Я все еще работаю с моими локальными модальными диалогами (LMD). См. этот вопрос для получения дополнительной информации. Теперь это работает нормально для простых случаев, но иногда в диалоге есть результат, о котором я хочу уведомить вызывающего. Поскольку вызов асинхронный с Show (), я не могу просто получить результат после вызова.

Итак, мой вопрос: как я могу вернуть одно или несколько значений из метода TLMD_Dialog.btnOkClick в метод TModule.myEvent?

У меня есть 3 единицы, вовлеченные в это: (Обратите внимание, что TLMD_Dialog наследуется от TAttracsForm)

// Module.pas
procedure myEvent(Sender: TObject);

procedure TModule.btnCallDlg(Sender: TObject);
begin
  if Supports(lhaHandle.CurrentBoldObject, IObject, vMyObject) then
    TModalDialog.Execute(param1, param2, myEvent);
end;

procedure TModule.myEvent(Sender: TObject);
begin
  // Some code that react on result of the LMD dialog
end;

// AttracsForm.pas
type
  TAttracsForm = class(TForm)
  procedure FormClose(Sender: TObject; var Action: TCloseAction);
  private
    fCallerForm: TForm;      // May be replaced by check PopupParent but a separate variable may be safer
    fOnAfterDestruction: TNotifyEvent;
  published
    procedure ShowLocalModal(aNotifyAfterClose: TNotifyEvent=nil);
  end;

procedure TAttracsForm.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if Assigned(fCallerForm) then      // fCallerForm not assinged means that ShowLocalModal is not called. The old way to show dialog is used
  begin
    ClientMainForm.ViewManager.UnLockCurrentView(fCallerForm as TChildTemplate);

    if Assigned(OnAfterDestruction) then
      OnAfterDestruction(Self);

    Action := caFree;
  end;
end;

{ Call to make a dialog modal per module.
  Limitation is that the creator of the module must be a TChildtemplate.
  Several modal dialogs cannot be stacked with this method.}
procedure TAttracsForm.ShowLocalModal(aNotifyAfterClose: TNotifyEvent);
begin
  fCallerForm := ClientMainForm.ViewManager.LockCurrentView;    // Lock current module and return it
  PopupParent := fCallerForm;
  OnAfterDestruction := aNotifyAfterClose;
  Show;
end;

// LMD_Dialog.pas (inherit from TAttracsForm)
class procedure Execute(aParam: IBoldObject; aNotifyEvent: TNotifyEvent);
class procedure TLMD_Dialog.Execute(aParam: IBoldObject; aNotifyEvent: TNotifyEvent);
begin
  with Self.Create(nil) do
  begin
    // Do preparation
    ShowLocalModal(aNotifyEvent);
  end;
end;

procedure TLMD_Dialog.btnOkClick(Sender: TObject);
begin
  // Do something before close down
  // Set Result of the dialog
  Close;
end;

Ответы [ 2 ]

2 голосов
/ 26 августа 2009

Это довольно просто, вы не используете TNotifyEvent, а пользовательский тип события с дополнительными параметрами для информации, которую вы хотите вернуть.

Простой пример получения имени файла и другого параметра (например, имени файла ZIP и уровня его сжатия:

type
  TReturnSaveZipFileDataEvent = procedure(Sender: TObject;
    const AFileName: string; ACompressionLevel: Cardinal) of object;

Теперь вместо объявления последнего параметра вашего Execute() метода типа TNotifyEvent вы объявляете его специальным типом события.

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

1 голос
/ 26 августа 2009

Время от времени я добавляю событие в базовый класс (в форме вашего случая), например:

//untested code, no doubt there are errors in it, it's the idea I want to pass

type
  TEventData = class(TObject)
  public
    property SomeCommonFieldForAncestorAndDescendants: String;
  end;

  TSomeBaseEvent = procedure (ASender: TObject; AEventData: TEventData) of object;

  TSomeBaseClassOrForm = class(TForm)
  protected
    FSomeEventData: TEventData;

    function GiveSomeDataClass: TClass; virtual;
    procedure DoOnSomeThing; virtual;
  public
    constructor Create; override;

    property OnSomething: TSomeBaseEvent;
  end;

Теперь вы можете позволить конструктору создавать экземпляр TEventData или потомка bij, вызывая GiveSomeDataClass.Create; Ваш потомок должен только переопределить GiveSomeDataClass и вернуть потомка TEventData, который он хочет использовать. Теперь у вас есть одно событие, объявленное в предке, возвращающее отправителя и объект данных, и последний может различаться по типам данных, которые он содержит. Теперь обработчик может использовать if (AEventData - TEventSpecialData) и действовать соответственно. Перед вызовом DoOnSomething вы можете установить значения FSomeEventData, даже в переопределении DoOnSomeThing в потомке, что угодно. ; -)

Альтернатива: вы можете сделать данные события общедоступным свойством и использовать Sender из обычного события для перехода к этому свойству из обработчика.

...