Как обрабатывать подписку на события универсального типа?

2

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

Я создал общий метод для отображения этих панелей:

private static T ShowPanel<T>(Control parent, params object[] parameters) where T: Panel
{
    T panelToShow = (T)Activator.CreateInstance(typeof(T), parameters);

    parent.Controls.Add(panelToShow);

    panelToShow.Dock = DockStyle.Fill;
    panelToShow.BringToFront();
    panelToShow.Show();

    return panelToShow;
}

Я использую его так, но я знаю, что должен быть лучший способ обработать подписку на события.

private void ShellButton_Click(object sender, EventArgs e)
{
    if (CurrentSelectedSite == null)
    {
        AlertSelectSite();
        return;
    }

    SystemViewPanel panel = ShowPanel<SystemViewPanel>(this, CurrentSelectedSite.Systems);

    panel.SystemsListbox.DoubleClick += new EventHandler(ShellAccessSystemSelected);
}

Есть куча кнопок, которые делают разные вещи. Если сайт имеет несколько систем, отображается SystemViewPanel, чтобы выбрать, в какой системе будет выполняться действие. Теперь, когда у меня есть это, я должен подписаться на другой обработчик именованного события, чтобы указать, какое действие я хочу выполнить, поэтому мой основной код формы становится загроможденным (т.е. ShellAccessSystemSelected, DownloadFileSystemSelected, ViewSystemSystemSelected и т.д.).

Изменить

Я думаю, что вещи могут быть обобщены в том, что я буду показывать панель, которая позволяет пользователю выбирать систему для большинства инструментов в моем приложении. Однако для каждого другого инструмента потребуется другое действие на основе инструмента, инициирующего создание SystemViewPanel.

  • 0
    Не совсем уверен, что вы пытаетесь с событиями здесь.
  • 0
    У вас есть SystemListbox или аналог на каждой вашей панели?
Показать ещё 2 комментария
Теги:
generics
events

2 ответа

0
Лучший ответ

Этот SystemViewPanel довольно незначителен. Все, что он делает, это способ выбора системного имени, поэтому я не хотел иметь 10 различных методов подписки на события, чтобы выбрать системное имя. Вот что я придумал:

private void ShellButton_Click(object sender, EventArgs e)
{
    if (CurrentSelectedSite == null)
    {
        AlertSelectSite();
        return;
    }

    SystemViewPanel systemSelectPanel = ShowPanel<SystemViewPanel>(this, CurrentSelectedSite.Systems);

    /*
    I decided that this since this panel is used quickly, I'd rather 
    keep the flow of what happening in the same place. The line
    above shows the panel, a double click later, and I'm back to doing
    what the ShellButton does. 

    I've exposed a SystemSelected event, which just wraps the panel 
    SystemsListBox.DoubleClick event.*/


    systemSelectPanel.SystemSelected += delegate(object s, EventArgs eArgs)
    {
        ListBox p = (ListBox)s;
        System system = (System)p.SelectedItem;

        if (system != null)
        {
            Process shell = new Process();
            shell.StartInfo = new ProcessStartInfo("cmd.exe",
            String.Format(@"/K psexec.exe \\{0} -u {1} -p {2} cmd.exe", system.IpAddress, CurrentSelectedSite.RemoteAccess.UserName, CurrentSelectedSite.RemoteAccess.DecryptedPassword));
            shell.StartInfo.WindowStyle = ProcessWindowStyle.Normal;
            shell.StartInfo.UseShellExecute = true;


            shell.Start();
        }

        this.Controls.Remove(p.Parent);
        p.Parent.Dispose();
        this.SearchPanel.BringToFront();
    };
}
0

Возможно, вы захотите обобщить поведение панели, нажав свой собственный базовый класс, который предоставляет те события, которые вы обычно ожидаете от своей панели. Это может быть началом. Вы также можете предоставить обработчики определенных событий непосредственно в конструкторе...

SystemViewPanel panel = ShowPanel<SystemViewPanel>(
  this, 
  panel => {
    //Do the stuff you would do on click event, panel impl ensures this 
    // gets called at the right moment
  },
  CurrentSelectedSite.Systems);

Обновление из-за комментария:

Вам нужно знать, какие параметры требуется вашей лямбда. Если вы довольны сигнатурой стандартного обработчика событий, вы можете просто использовать "EventHandler" в качестве типа параметра. Тогда ваша лямбда выглядела бы как

(sender, args) => //Do stuff

Кроме того, если ваша вызываемая функция просто требует панели, вы должны использовать один из делегатов Action < T [, T2 и т.д.] > , который позволяет вам выражать методы с параметрами но нет возвращаемых значений.

Если вы хотите вернуть какое-то значение из вашего вызванного lmbda, которое затем будет обработано вызывающей стороной (вашей панелью), вы должны использовать любой из Func < T, [T1 и т.д.]. > делегаты

  • 0
    Хорошо, я вижу, куда ты идешь. Какой тип аргумента я бы передал этому (я все еще не очень хорош в аргументе типа Func <что-то, SystemViewPanel>).
  • 0
    @ Фрэнк, я отправил свой собственный ответ, но твой вклад дал мне идею. Не стесняйтесь, чтобы демократия SO определяла, является ли это приемлемым подходом.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню