Как создать функцию, которая получает в качестве параметра динамическую функцию?

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

Вот мой код:

public static void ShowDialogBox(Context context, Function dynamicFunction)
{
    Dialog popupDialog = new Dialog(context);
    popupDialog.SetContentView(Resource.Layout.dialog_dynamic);
    popupDialog.Window.SetSoftInputMode(SoftInput.AdjustResize);
    popupDialog.Window.SetBackgroundDrawableResource(Android.Resource.Color.Transparent);
    popupDialog.Show();

    TextView title = popupDialog.FindViewById<TextView>(Resource.Id.dialog_title);
    TextView content = popupDialog.FindViewById<TextView>(Resource.Id.dialog_content);
    ImageView icon = popupDialog.FindViewById<ImageView>(Resource.Id.dialog_icon);
    Button actionButton = popupDialog.FindViewById<Button>(Resource.Id.dialog_action_button);

    popupDialog.FindViewById<ImageButton>(Resource.Id.dialog_close).Click += delegate { popupDialog.Dismiss(); };
    popupDialog.FindViewById<Button>(Resource.Id.dialog_cancel_button).Click += delegate { popupDialog.Dismiss(); };
    
    actionButton.Click += dynamicFunction;
}

*Обратите внимание, что параметр Function является лишь примером. Также я сделаю текст и содержимое в этом диалоговом окне параметром.

Пример сценария:

  1. Если я отправлю функцию GetCurrentDate в это диалоговое окно, при нажатии кнопки действия она получит текущую дату.
  2. Если я отправлю функцию OpenBluetooth в это диалоговое окно, при нажатии кнопки действия откроется окно Bluetooth.

Можно ли отправить в эту функцию ShowDialogBox другую функцию и запускать ее при нажатии кнопки действия? Моя цель здесь — сделать мой код чистым и простым в использовании.

Вы уже изучали использование делегатов? Вы можете использовать делегат в качестве параметра, и это будет функция, которая будет выполняться динамически. Вот вопрос, на который уже ответили с тем же требованием, что и ваш вопрос. stackoverflow.com/questions/2082615/…

Nico 05.05.2022 11:56

по моему опыту, общий диалог (или форма) — это тупиковый путь. Я имею в виду, что стоимость бизнес-уровня/UI, чтобы иметь возможность адаптироваться ко многим (разным) ситуациям, и стоимость создания нескольких компонентов в 99% случаев в пользу последних. Если вы хотите, вы можете получить некоторое преимущество с умным шаблоном композиции, но, опять же, оно того не стоит, если диалоги довольно просты.

Mario Vernari 05.05.2022 12:01
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
2
61
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Как уже прокомментировал @Nico, вы можете использовать Func или делегата в качестве параметра. Вместо этого я предлагаю вам использовать Action.

Clicked событие на Xamarin.Forms.Button использует обработчик событий с подписью void OnClicked(object? sender, EventArgs e). Поэтому в вашей подписи будет использоваться параметр Action<object?, EventArgs>.

Несколько замечаний:

  • Если вы не используете в своем проекте ссылочные типы, допускающие значение NULL, опустите вопросительные знаки.
  • Вам нужно проверить параметр для null, прежде чем назначать его событию Clicked
  • Вызов Action ничего не возвращает. Если вы хотите «получить текущую дату», ваше действие должно записать текущую дату в поле или элемент управления
  • Если вашей функции нужны другие параметры, вам нужно передать делегат (или обернуть вызов функции в функцию с параметрами sender и e: ShowDialogBox(context, (sender, e) => MyFunction("other data"))
Ответ принят как подходящий

Вам может помочь объектная ориентация: вы можете абстрагировать свою функцию в класс, а затем получить любой специализированный класс функции для реализации вашего конкретного действия. Что-то вроде следующего:

abstract class ActionClassBase
{
    public abstract void Action();

    private string data = "";
    public string Data { get { return data; } set { data = value; } }
}

class GetCurrentDateAction : ActionClassBase
{
    public override void Action()
    {
        Data = DateTime.Now.ToString();
    }
}

class OpenBlueToothAction : ActionClassBase
{
    public override void Action()
    {
        Data = "BlueTooth opened";
    }
}


public static void ShowDialogBox(Context context, ActionClassBase action)
{
    Dialog popupDialog = new Dialog(context);
    popupDialog.SetContentView(Resource.Layout.dialog_dynamic);
    popupDialog.Window.SetSoftInputMode(SoftInput.AdjustResize);
    popupDialog.Window.SetBackgroundDrawableResource(Android.Resource.Color.Transparent);
    popupDialog.Show();

    TextView title = popupDialog.FindViewById<TextView>(Resource.Id.dialog_title);
    TextView content = popupDialog.FindViewById<TextView>(Resource.Id.dialog_content);
    ImageView icon = popupDialog.FindViewById<ImageView>(Resource.Id.dialog_icon);
    Button actionButton = popupDialog.FindViewById<Button>(Resource.Id.dialog_action_button);

    popupDialog.FindViewById<ImageButton>(Resource.Id.dialog_close).Click += delegate { popupDialog.Dismiss(); };
    popupDialog.FindViewById<Button>(Resource.Id.dialog_cancel_button).Click += delegate { popupDialog.Dismiss(); };

    actionButton.Click += (sender, ev) => action.Action();
}

Кроме того, при таком подходе очень легко добавлять новые функции: просто создайте новый класс и переопределите метод Action().

Другой вопрос, как я могу закрыть диалоговое окно с помощью action.Action()?

Elohist 06.05.2022 02:54

Почему вы хотите использовать action.Action(), чтобы закрыть диалоговое окно? В вашем коде уже есть кнопка отмены. Кроме того, для закрытия диалогового окна необходимо вызвать метод Dismiss(). Поэтому, если вы хотите закрыть его с помощью action.Action(), вам нужно заставить ActionClassBase получить экземпляр диалога, а затем вызвать метод Dismiss(). @Элогист

Liyun Zhang - MSFT 06.05.2022 03:57

Я хочу закрыть его после выполнения action.Action(). Как я могу передать свое диалоговое окно в ActionClassBase?

Elohist 06.05.2022 04:21

Вы можете попробовать код в моем ответе. @Elohist

Liyun Zhang - MSFT 06.05.2022 04:38

@Elohist просто добавьте ссылку на Window и логический флаг, чтобы решить, закрывать или нет базовый класс (устанавливайте их внутри метода ShowDialogBox). Затем на каждом Action вы можете решить, закрывать диалог или нет.

Marco Beninca 06.05.2022 08:29

Вы можете создать Dialog в ActionClassBase и вызвать метод Dismiss() в Action(). Такие как

abstract class ActionClassBase
{
  public  Dialog popupDialog;
  public abstract void Action();

  private string data = "";
  public string Data { get { return data; } set { data = value; } }
  }

class GetCurrentDateAction : ActionClassBase
{
  public override void Action()
  {
    Data = DateTime.Now.ToString();
    base.popupDialog.Dismiss();
  }
}

class OpenBlueToothAction : ActionClassBase
{
  public override void Action()
  {
    Data = "BlueTooth opened";
    base.popupDialog.Dismiss();
  }
}

А затем передайте диалог в ActionClassBase в файле ShowDialogBox(Context context, Function dynamicFunction) . Такие как:

Dialog popupDialog = new Dialog(context);
popupDialog.SetContentView(Resource.Layout.dialog_dynamic);
popupDialog.Window.SetSoftInputMode(SoftInput.AdjustResize);
popupDialog.Window.SetBackgroundDrawableResource(Android.Resource.Color.Transparent);
dynamicFunction.popupDialog = popupDialog;

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