Модераторы: Partizan, gambit
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> паттерн Command, ? 
V
    Опции темы
_Dream
Дата 15.5.2007, 18:09 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 133
Регистрация: 4.11.2006
Где: Там

Репутация: нет
Всего: нет



читал тут и тут
не понял как мне разрулить ситуацию(из-за чего и был выбран этот паттерн)
у меня есть форма на ней контрол на нем еще и т д и мне надо чтоб по нажатию кнопки на форме(самой внешней) было произведено некое действие на самом внутреннем контроле.
как быть?
--------------------
Noone dies a virgin. Life screws us all...
PM MAIL ICQ GTalk   Вверх
ivashkanet
Дата 16.5.2007, 09:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодю потиху
****


Профиль
Группа: Участник Клуба
Сообщений: 3684
Регистрация: 23.2.2006
Где: Гомель, Беларусь

Репутация: 47
Всего: 149



Цитата(_Dream @  15.5.2007,  17:09 Найти цитируемый пост)
у меня есть форма на ней контрол на нем еще и т д и мне надо чтоб по нажатию кнопки на форме(самой внешней) было произведено некое действие на самом внутреннем контроле.

А причем здесь команда?
Тут подходит цепочка обязанностей

Только вот немного непонятно. Что будет если этих "самых внутренних" будет больше одного. Кто должен получить запрос?
(в обратном порядке все нормально получается)

Пример:
Код

    // Интерфейс, который должны реализовывать все члены цепочки
    public interface IMessageHandler
    {
        void HandleMessage();
    }

    // Пример панели, которая реализует этот интерфейс
    public class PanelWithMessageHandler : Panel, IMessageHandler
    {
        public void HandleMessage()
        {
            bool lowLevelControl = true;
            // Если мы не контрол нижнего уровня, то передаем сообщение всем 
            // поолучателям уровня ниже
            foreach (Control control in Controls)
            {
                if (control is IMessageHandler)
                {
                    (control as IMessageHandler).HandleMessage();
                    lowLevelControl = false;
                }
            }

            // Если мы не нашли того, кто будет обрабатывать 
            // наш запрос, то мы сами его должны обработать
            if (lowLevelControl)
            {
                // Если мы контрол нижнего уровня, то обрабатываем сообщение сами
                processMessage();
            }
        }

        private void processMessage()
        {
            MessageBox.Show("Ура", "Я получил сообщение");
        }
    }



P.S. Код, определяющий принадлежность класса интерфейсу (control is IMessageHandler), требует большого количества процессорного времени, так что если передача сообщений будет частой есть смысл хранить коллекцию контролов, которые реализуют IMessageHandler и наполнять ее по мере добавления контролов в коллекцию Controls

Добавлено через 2 минуты и 31 секунду
P.P.S. В моем случае запрос будет обработан !всеми! контролами, у которых в коллекции нет дочерних контролов-обработчиков

Это сообщение отредактировал(а) ivashkanet - 16.5.2007, 09:09
PM MAIL WWW ICQ   Вверх
tol05
Дата 16.5.2007, 09:27 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



ИМХО это не есть оптимальный вариант smile
зачем нам по каждому чиху проходить по всей коллекции контролов?
Цитата(ivashkanet @  16.5.2007,  09:07 Найти цитируемый пост)
foreach (Control control in Controls)


Т.е. пришло, напр. событие MouseMove, и мы 100 контролов опрашиваем, один нашли.
пришло MouseClick, оказалось, вообще ни один не подписан, самим надо обрабатывать. А мы всех по очереди подергали уже. smile
Если у нас 50-100 контролов и 20 событий, то сколько комбинаций получиться?

Предлагаю: в классе формы объявить делегат (или событие), на которое подписываются внутренние контролы. На все внешние события подписаться формой и когда форма отловит событие - дергать наш делегат(событие).
Кто подписан, тот и получит.

Допустим, есть форма form1 и три кнопки button1, button2, button3
Код

public form1()
{
  InitializeComponent();
  this.MouseClick += button1.OnMainformClick();
  this.MouseClick += button2.OnMainformClick();
  this.DoubleClick += button1.OnMainformDoubleClick();
  this.DoubleClick += button3.OnMainformDoubleClick();
  this.DoubleClick += button3.OnMainformDoubleClick();
  this.MouseMove += button3.OnMainformMouseMove();


все, когда форма получит событие, она вызовет зарегистрированный обработчик внутреннего контрола.
Если обработчиков событий формы мы не регистрировали, то только внутренний контрол и обработает.

К тому же, никакого лишнего кода по проверке делегата на null. Пользуемся концентрированным опытом мелкомягких.  smile 

З.Ы. smile
Да, отжег я здоровски.
Для того, чтобы получилось то, что я написал, нужно создать свой класс, наследник Button и button1, button2, button3 сделать его экземплярами... Определить в них эти обработчики.
ну, тогда подписаться формой на все события, и в них вызывать, события стандартных Button, например,
Код

private void form1_Click(object sender, EventArgs e)
    {
button1_Click(sender, e);
    }


Это сообщение отредактировал(а) tol05 - 16.5.2007, 09:40


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
ivashkanet
Дата 16.5.2007, 09:44 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодю потиху
****


Профиль
Группа: Участник Клуба
Сообщений: 3684
Регистрация: 23.2.2006
Где: Гомель, Беларусь

Репутация: 47
Всего: 149



Цитата(tol05 @  16.5.2007,  08:27 Найти цитируемый пост)
зачем нам по каждому чиху проходить по всей коллекции контролов?

Во-прервых, не по каждому чиху, а только при запуске HandleMessage()
Во-вторых, я уже об этом упомянул 
Цитата(ivashkanet @  16.5.2007,  08:07 Найти цитируемый пост)
P.S. Код, определяющий принадлежность класса интерфейсу (control is IMessageHandler), требует большого количества процессорного времени, так что если передача сообщений будет частой есть смысл хранить коллекцию контролов, которые реализуют IMessageHandler и наполнять ее по мере добавления контролов в коллекцию Controls

В-третьих, если создать свою личную "коллекцию контролов, которые реализуют IMessageHandler и наполнять ее...", то скорость вызова будет ничуть не меньше, чем при событиях.
В-четвертых, класс выбрасывающий событие НЕ ДОЛЖЕН интересоваться кто получил сообщение о событии и вообще получил ли кто-то его. В твоем же случае, нужно смотреть зарегистрированы ли обработчики на событие.

Добавлено через 1 минуту и 44 секунды
Цитата(tol05 @  16.5.2007,  08:27 Найти цитируемый пост)
Для того, чтобы получилось то, что я написал, нужно создать свой класс, наследник

А без наследования никак  smile 
PM MAIL WWW ICQ   Вверх
tol05
Дата 16.5.2007, 09:50 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



ivashkanet, 
Цитата(ivashkanet @  16.5.2007,  09:44 Найти цитируемый пост)
не по каждому чиху, а только при запуске HandleMessage()

я как раз это и имел в виду. По каждому запуску HandleMessage() на панели, она будет опрашивать ВСЕ свои контролы.

Цитата(ivashkanet @  16.5.2007,  09:44 Найти цитируемый пост)
 класс выбрасывающий событие НЕ ДОЛЖЕН интересоваться кто получил сообщение о событии и вообще получил ли кто-то его

вот с этим я как раз полностью согласен.



--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
tol05
Дата 16.5.2007, 11:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



 smile 
И все-таки мне что-то не нравится. Что если нужно, чтобы сообщение обработалось только частью вложенных элементов? Или и вложенными, и контейнерами?

Предлагаю дополнить твой код,  ivashkanet
Код

// Интерфейс, который должны реализовывать все члены цепочки
    public interface IMessageHandler
    {
        void HandleMessage(EventArgs e);
        //Подписывался ли я сам на обработку?
        bool ConsumeOnEvent {get; set;}
        //вложенные контролы, но только те, кто может обрабатывать посторонние события
        List<IMessageHandler> Handlers {get;}
    }

    // Пример панели, которая реализует этот интерфейс
    public class PanelWithMessageHandler : Panel, IMessageHandler
    {
        public PanelWithMessageHandler()
        {
           //Здесь немного муторно, зато один раз цикл, а не при каждом вызове HandleMessage()
           InitializeComponent();

           Handlers = new List<IMessageHandler>();
           foreach (Control control in Controls)
           {
               if (control is IMessageHandler)
               {
                  Handlers.Add(control);
               }
            }
        }

        //как раз private - клиенту это не надо. Ему нужна только processMessage
        private void HandleMessage(EventArgs e)
        {
            foreach (IMessageHandler control in Handlers)
            {
                control.HandleMessage(e);
            }

            if (ConsumeOnEvent)
            {
                processMessage(e);
            }
        }

        //только private void processMessage(EventArgs e) делать нельзя. 
        //как клиент кнопки напишет логику и подключит реальный обработчик (или несколько)
        //к контролу?
        public event EventHandler processMessage;

        private bool consume;

        public bool ConsumeOnEvent 
        {
          get { return consume;} 
          set 
          {
             consume = value;
             if(value)
             {
                 this.processMessage += ProcessMessage;
             }
             else
             {
                 this.processMessage -= ProcessMessage;
             }
           }
        }

        private void ProcessMessage(EventArgs e)
        {
            MessageBox.Show("Ура", "Я получил сообщение");
           //Вытягиваем инфу из "e", приводим ее к типу ожидаемого EventArgs
        }
    } 


Это сообщение отредактировал(а) tol05 - 16.5.2007, 11:08


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
_Dream
Дата 16.5.2007, 11:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 133
Регистрация: 4.11.2006
Где: Там

Репутация: нет
Всего: нет



спасибо за помощь.. решено сделать так..
есть некий класс КомандМэнеджер, который реализует интерфейс ИКомандМэнеджер(в интерфейсе методы адд,дел)
в этом же классе есть свойство возвращающее наш контрол самого нижнего уровня. КомандМэнеджер интернал и лежит рядом с контролом_нижнего_уровня. у самого контрола есть свойство возвращающее ИКомандМэнеджер. и просто вытягиваем наверх наш обьект КомандМэнеджер(до уровня верхей формы) и все.. ну и все это через интерфейс..
--------------------
Noone dies a virgin. Life screws us all...
PM MAIL ICQ GTalk   Вверх
ivashkanet
Дата 16.5.2007, 11:30 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодю потиху
****


Профиль
Группа: Участник Клуба
Сообщений: 3684
Регистрация: 23.2.2006
Где: Гомель, Беларусь

Репутация: 47
Всего: 149



Цитата(tol05 @  16.5.2007,  10:07 Найти цитируемый пост)
        //вложенные контролы, но только те, кто может обрабатывать посторонние события
        List<IMessageHandler> Handlers {get;}

Гы, у меня был такой вариант, но:
1)  я счел его сложным и не стал его выкладывать
2) IMessageHandler это интерфейс, который реализуется, а не наследуется, так что эту бороду с коллекцией нужно нужно реализовывать в каждом классе
3) основная причина клиенту интерфейса побоку на эту коллекцию (ему о ней вообще знать не желательно, иначе наступит момент, когда ее заюзают, что неправильно), так что она должна быть приватная, чего не может обеспечить интерфейс.


P.S. Пройдусь по твоему коду:
Цитата(tol05 @  16.5.2007,  10:07 Найти цитируемый пост)
        //как раз private - клиенту это не надо. Ему нужна только processMessage

Его нельзя объявить приватным, так как это метод интерфейса (компилятор не простит).
Цитата(tol05 @  16.5.2007,  10:07 Найти цитируемый пост)
       public event EventHandler processMessage;

Если уж наружу выставлен эвент, то именно его и нужно было объявлять в интерфейсе.
Клиент не обязан ничего знать о Панели и др. контролах, ему нужна только функциональность IMessageHandler
Цитата(tol05 @  16.5.2007,  10:07 Найти цитируемый пост)
this.processMessage += ProcessMessage;

Не хочу обидеть, но подписка и отписка на свой собственный эвент --- это круто.
Цитата(tol05 @  16.5.2007,  10:07 Найти цитируемый пост)
Handlers.Add(control);

Вместо цикла в конструкторе лучше подписаться на два события класса Control: ControlAdded и ControlRemoved
Цитата(tol05 @  16.5.2007,  10:07 Найти цитируемый пост)
        private void HandleMessage(EventArgs e)

Кто вызывает этот приватный метод я так и не понял

Добавлено через 4 минуты и 29 секунд
Цитата(_Dream @  16.5.2007,  10:29 Найти цитируемый пост)
КомандМэнеджер

Ничего не понял  smile 
PM MAIL WWW ICQ   Вверх
_Dream
Дата 16.5.2007, 11:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 133
Регистрация: 4.11.2006
Где: Там

Репутация: нет
Всего: нет



если упростить то я тяну наверх контрол
--------------------
Noone dies a virgin. Life screws us all...
PM MAIL ICQ GTalk   Вверх
ivashkanet
Дата 16.5.2007, 11:42 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодю потиху
****


Профиль
Группа: Участник Клуба
Сообщений: 3684
Регистрация: 23.2.2006
Где: Гомель, Беларусь

Репутация: 47
Всего: 149



Цитата(_Dream @  16.5.2007,  10:37 Найти цитируемый пост)
тяну

А это как?
PM MAIL WWW ICQ   Вверх
_Dream
Дата 16.5.2007, 11:46 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Шустрый
*


Профиль
Группа: Участник
Сообщений: 133
Регистрация: 4.11.2006
Где: Там

Репутация: нет
Всего: нет



ну по событиям.
то есть у всех участников цепочки(кто тянет) реализован интерфейс(например с 1м полем) и при определенном условии(например я выбрал свой грид на контроле_нижнего_уровня) у меня срабатывает мое событие. на него подписан контрол_более_высокого_уроня. он получает данные от того кто зажег событие и это вызывает следуеще событие на еще 1 уровень вверх.. и таким образом я тяну данные на самый верх.. вроде это стандартный подход
--------------------
Noone dies a virgin. Life screws us all...
PM MAIL ICQ GTalk   Вверх
tol05
Дата 16.5.2007, 12:01 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



ivashkanet, да, согласен со всеми твоими упреками. Я в блокноте писал, так что 
Цитата(ivashkanet @  16.5.2007,  11:30 Найти цитируемый пост)
компилятор не простит
 не проверял.

Цитата(ivashkanet @  16.5.2007,  11:30 Найти цитируемый пост)
подписка и отписка на свой собственный эвент

действительно, лажа получилась smile

HandleMessage делаем открытым, ProcessMessage ни фиг не нужен, пусть вызовом HandleMessage вызываются обработцики для текущего контрола и HandleMessage для вложенных

ConsumeOnEvent не нужен, только внутри класса используется

код сильно упростился smile

Код

// Интерфейс, который должны реализовывать все члены цепочки
    public interface IMessageHandler
    {
        void HandleMessage(EventArgs e);
        //вложенные контролы, но только те, кто может обрабатывать посторонние события
        List<IMessageHandler> Handlers {get;}
        event EventHandler processMessage;
    }

    // Пример панели, которая реализует этот интерфейс
    public class PanelWithMessageHandler : Panel, IMessageHandler
    {
        public event EventHandler processMessage;
        private bool consume;
        List<IMessageHandler> Handlers;

        public List<IMessageHandler> Handlers
       { get { return Handlers; } }

        public PanelWithMessageHandler()
        {
           InitializeComponent();

           Handlers = new List<IMessageHandler>();
           this.ControlAdded += delegate (object sender, ControlEventArgs e) 
           {
               if (control is IMessageHandler)
               {
                  Handlers.Add(e.Control);
               }

           };
           this.ControlRemoved  += delegate (object sender, ControlEventArgs e)
           {
               if (control is IMessageHandler)
               {
                   Handlers.Remove(e.Control);
               }

            };
        }

        public void HandleMessage(EventArgs e)
        {
            foreach (IMessageHandler control in Handlers)
            {
                control.HandleMessage(e);
            }

            if (consume)
            {
                processMessage(e);
            }
        }
   }  
 

в принципе и Handlers в интерфейсе не нужен, но я оставил и сделал свойчтво доступа. Пусть будет smile

Цитата(ivashkanet @  16.5.2007,  11:30 Найти цитируемый пост)
Не хочу обидеть

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

Это сообщение отредактировал(а) tol05 - 16.5.2007, 12:03


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
ivashkanet
Дата 16.5.2007, 13:23 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Кодю потиху
****


Профиль
Группа: Участник Клуба
Сообщений: 3684
Регистрация: 23.2.2006
Где: Гомель, Беларусь

Репутация: 47
Всего: 149



_Dream, вот теперь понятно, но заявлено было наоборот: 
Цитата(_Dream @  15.5.2007,  17:09 Найти цитируемый пост)
у меня есть форма на ней контрол на нем еще и т д и мне надо чтоб по нажатию кнопки на форме(самой внешней) было произведено некое действие на самом внутреннем контроле.
 Т.е. была передача сообщения сверху вниз.

_Dream, есть небольшой комментарий: механизм событий ненадежен. Что будет если кто-то забудет подписаться на это событие? Тогда оно просто уйдет вникуда. Через 3-4 месяца вы на эту ошибку будете с большими глазами смотреть.


P.S. tol05, опять есть комментарии пот твоему коду smile
Например, из HandleMessage и processMessage в интерфейсе кто-то лишний
PM MAIL WWW ICQ   Вверх
tol05
Дата 16.5.2007, 13:36 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
***


Профиль
Группа: Участник Клуба
Сообщений: 1632
Регистрация: 21.12.2006
Где: Харьков

Репутация: 63
Всего: 170



Никто не лишний  smile 

processMessage - для подписки обработчиков (хранения методов, что будут обработку проводить и их вызова). Если его из интерфейса убрать, то нет гарантии, что внутри нашего контрола будут контролы, которые могут подписываться.

HandleMessage - для инициирования обработки и передачи управления вложенным контролам. Если его убрать, то как вложенные контролы получат сообщение?

т.е. HandleMessage - для работы с сообщением по вертикали, а processMessage - по горизонтали (в рамках одного, текущего контрола)

З.Ы. Другое дело, что consume явно не работает. Убрать его нафиг и вместо него все-таки 
Код

if(processMessage != null)


так правильнее будет, как не крути

Это сообщение отредактировал(а) tol05 - 16.5.2007, 13:39


--------------------
На хорошей работе и сны хорошие снятся.
PM MAIL   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Прежде чем создать тему, посмотрите сюда:
mr.DUDA
THandle

Используйте теги [code=csharp][/code] для подсветки кода. Используйтe чекбокс "транслит" если у Вас нет русских шрифтов.
Что делать если Вам помогли, но отблагодарить помощника плюсом в репутацию Вы не можете(не хватает сообщений)? Пишите сюда, или отправляйте репорт. Поставим :)
Так же не забывайте отмечать свой вопрос решенным, если он таковым является :)


Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, mr.DUDA, THandle.

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | Общие вопросы по .NET и C# | Следующая тема »


 




[ Время генерации скрипта: 0.0715 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.