Как запустить процедуру в нескольких кадрах?

У меня есть приложение с бесконечным (многим) количеством кадров, которые динамически добавляются и удаляются. Я никогда не знаю, какие из них активны, а какие неактивны.

У всех из них есть такая процедура:

procedure DoAfterPermissions();
begin
  // Code to run after permissions have been refreshed
end;

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

Как это может быть сделано? Я даже не знаю, с чего начать.

Обновлено: это приложение FMX, работающее на Windows, Android и iOS.

Идеальный кандидат для System.Messaging.

Uwe Raabe 05.07.2024 09:32

Почему бы не использовать шаблон наблюдателя с System.Classes.TComponent.Observers, который TFrame уже предоставляется как свойство. Хотя класс TObservers был добавлен в Delphi для обеспечения функционирования LiveBindings, его также можно использовать без использования LiveBindings.

SilverWarior 05.07.2024 09:41
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
2
139
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Я бы предложил две вещи:

  1. Пусть все классы фреймов наследуются от общего базового класса (или реализуют общий интерфейс), который определяет метод DoAfterPermissions(), а затем все фреймы переопределяют его.

  2. Сохраните все экземпляры фреймов в списке, типом элемента которого является указанный выше базовый класс/интерфейс.

Таким образом, вы можете просто перебирать список, когда это необходимо, вызывая метод непосредственно в каждом кадре.

Например:

type
  TMyFrameBase = class(TFrame)
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure DoAfterPermissions; virtual; abstract;
  end;

var
  MyFrames: TList<TMyFrameBase>;

...

constructor TMyFrameBase.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  MyFrames.Add(Self);
end;

destructor TMyFrameBase.Destroy;
begin
  MyFrames.Remove(Self);
  inherited Destroy;
end;

initialization
  MyFrames := TList<TMyFrameBase>;
finalization
  MyFrames.Free;
type
  TMyFrame = class(TMyFrameBase)
  public
    procedure DoAfterPermissions; override;
  end;

procedure TMyFrame.DoAfterPermissions;
begin
  // do something...
end;
RefreshPermissions;
for I := 0 to MyFrames.Count-1 do
  MyFrames[I].DoAfterPermissions;

Спасибо за ответ. Не могли бы вы привести пример короткого кода для пункта номер 2?

JakesF 10.07.2024 00:08

Я добавил пример

Remy Lebeau 10.07.2024 02:04

Вы можете использовать событие многоадресной рассылки.

Если ваше приложение основано на Windows, вы можете изучить возможность использования широковещательной рассылки настраиваемых сообщений и реализации обработчиков сообщений там, где это необходимо.

В качестве альтернативы или если вам нужно получать уведомления об объектах, которые не способны принимать сообщения, вы можете рассмотреть событие многоадресной рассылки (один отправитель, 0..N получателей).

Я не знаю, добавила ли Delphi поддержку многоадресных событий в последние годы; если нет, вы можете использовать реализацию, которую я собрал несколько лет назад.

Это не тестировалось с последними версиями Delphi, но не использует никаких экзотических методов и все равно должно работать. Если нет, не стесняйтесь изменить его, чтобы исправить любые проблемы (если да, дайте мне знать?). :)

В README упоминается «duget», инструмент управления зависимостями, который я также реализовал и созданный по образцу nuget. Это не было опубликовано, так как я так и не смог заставить его работать с частными репозиториями файловой системы, прежде чем отойти от Delphi. :(

Но в случае с пакетом deltics.multicast это не так уж и важно; единственная зависимость проекта — это проект deltics.inc, который предоставляет версию Delphi и возможности компилятора $DEFINE в файле .inc; вы также можете взять это с github.

Это эффективно обеспечивает реализацию подхода, описанного Реми, используя события Delphi для доставки уведомлений, а не полагаясь на определенную иерархию классов (виртуальные методы) или использование интерфейсов.

Применение

Многоадресную версию TNotifyEvent предоставляет TMulticastNotify.

В каком-нибудь известном синглтоне вы должны предоставить экземпляр этого (источник события). Каждый кадр (и все остальное, что хочет реагировать на событие) будет реализовывать обработчик TNotifyEvent и регистрировать его в источнике события.

Если получатели эфемерны (то есть они могут быть уничтожены после регистрации событий), им следует явно удалить свой обработчик из источника события в своем деструкторе (самый простой подход) или инкапсулировать ссылку на событие TOnDestroy (также часть deltics.multicast код).

В вашем случае подход TOnDestroy кажется излишне сложным; это задокументировано в коде, если вам интересно.

Простая иллюстрация:

TPermissions = class(TComponent)
private
  fOnChanged: TMulticastNotify;
  procedure DoChanged;
public
  constructor Create(aOwner: TObject); override;
  property OnChanged: TMulticastNotify read fOnChanged;
end;

var Permissions: TPermissions; // unit scoped singleton, initialised somewhere as required

// ----

constructor TPermissions.Create(aOwner: TObject);
begin
  inherited Create(aOwner);

  fOnChanged := TMulticastNotify.Create(self);
end;

procedure TPermissions.DoChanged;
begin
  fOnChanged.DoEvent;
end;

Обратите внимание, что событию OnChanged нужен только аксессор read, поскольку он не изменяется при добавлении получателя; это объект, который управляет списком получателей с помощью открытых методов (Add/Remove).

Затем вы можете реализовать класс для получения события многоадресной рассылки и вызова соответствующего события одноадресной рассылки (если оно назначено). Затем экземпляр этого класса можно скомпоновать внутри фрейма или любого другого класса, который необходимо уведомлять об изменениях разрешений (или вы можете просто реализовать аналогичный код для каждого класса, который хочет подписаться на события изменения разрешений):

TPermissionsChanged = class
private
  fOnPermissionsChanged: TNotifyEvent;
  procedure DoPermissionsChanged(aSender: TObject);
public
  constructor Create; override;
  destructor Destroy; override;
  property OnPermissionsChanged: TNotifyEvent read fOnPermissionsChanged write fOnPermissionsChanged;
end;

// ---

constructor TPermissionsChanged.Create;
begin
  inherited Create;

  // 'Permissions' is the well-known (i.e. public) singleton instance of TPermissions
  Permissions.OnChanged.Add(self.DoPermissionsChanged)
end;

destructor TPermissionsChanged.Destroy;
begin
  Permissions.OnChanged.Remove(self.DoPermissionsChanged);
  inherited;
end;

procedure TPermissionsChanged.DoPermissionsChanged(aSender: TObject);
begin
  if Assigned(fOnPermissionsChanged) then
    fOnPermissionsChanged(aSender);
end;

У Delphi есть собственная система обмена сообщениями System.Messaging (по крайней мере, начиная с XE6), предназначенная, как я полагаю, для FMX, который не может полагаться на сообщения Windows, но она не ограничивается FMX. См. Отправка и получение сообщений с использованием RTL.

Philip J. Rayment 05.07.2024 07:09

Спасибо @PhilipJ.Rayment, выглядит как (очень простая) версия MediatR (из .net). Кому-то это может быть полезно, хотя, ИМХО, менее элегантно. ymmv

Deltics 06.07.2024 00:53

Другие вопросы по теме