none
Реализация MVC в приложении RRS feed

  • Вопрос

  • В соседней теме, Petalvik и Kirill помогли разобраться с сериализацией, за что вам большое спасибо. Теперь прошу помочь (Хотелось бы услышать ответ от Petalvik :) ) с MVC, да и в общем, с некоторыми базовыми вещами. Т.к. читая msdn, или книги, все-равно, очень многое не понятно. Вот ссылка на солюшн VS 2012 - http://webfile.ru/6355632. В коде, я в комментах, попытался, где смог, описать каждую, ну или почти каждую строчку кода, возможно не очень правильно?!

    В предыдущей теме, внутри приложения (PhoneBook) MVC реализован не был. Сразу скажу, что код не мой, вернее то, что пытался писать я переиначили в виде MVC. Тут код выкладывать не стал, т.к. нет спойлеров, и мой пост получится плохо читабельным, я думаю.

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

    Вот схематически, как я представляю работу этого приложения в рамках MCV. На картинке изобразил схему, кто за что отвечает в приложении http://webfile.ru/6355495

    Спасибо.

    3 февраля 2013 г. 18:30

Ответы

  • Добрый день.

    Я уже сто лет под WinForms не программирую, но, если бы я решал данную задачу, то:

    Модель: Класс персона, массив персон, сериализация и десереализация.

    Вью: Главная форма и форма добавления/редактирования элемента. Для удаления нужно просто окно с вопросом: "Вы точно хотите удалить эту запись?" и кнопками: да, нет. На форме добавления/редактирования, я бы добавил кнопку отмена.

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

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

    Из контроллеров есть с ссылки на модель и на интерфейсы, через которые они взаимодействуют с вьюхами.

    • Предложено в качестве ответа Petalvik 4 февраля 2013 г. 12:53
    • Отменено предложение в качестве ответа Andrey Langovoy 4 февраля 2013 г. 13:35
    • Помечено в качестве ответа Abolmasov Dmitry 8 февраля 2013 г. 10:37
    • Снята пометка об ответе Andrey Langovoy 11 февраля 2013 г. 12:48
    • Помечено в качестве ответа Abolmasov Dmitry 18 февраля 2013 г. 14:06
    4 февраля 2013 г. 6:24
    Отвечающий

Все ответы

  • Добрый день.

    Я уже сто лет под WinForms не программирую, но, если бы я решал данную задачу, то:

    Модель: Класс персона, массив персон, сериализация и десереализация.

    Вью: Главная форма и форма добавления/редактирования элемента. Для удаления нужно просто окно с вопросом: "Вы точно хотите удалить эту запись?" и кнопками: да, нет. На форме добавления/редактирования, я бы добавил кнопку отмена.

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

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

    Из контроллеров есть с ссылки на модель и на интерфейсы, через которые они взаимодействуют с вьюхами.

    • Предложено в качестве ответа Petalvik 4 февраля 2013 г. 12:53
    • Отменено предложение в качестве ответа Andrey Langovoy 4 февраля 2013 г. 13:35
    • Помечено в качестве ответа Abolmasov Dmitry 8 февраля 2013 г. 10:37
    • Снята пометка об ответе Andrey Langovoy 11 февраля 2013 г. 12:48
    • Помечено в качестве ответа Abolmasov Dmitry 18 февраля 2013 г. 14:06
    4 февраля 2013 г. 6:24
    Отвечающий
  • Когда придет более полное понимание некоторых базовых вещей, возможно, задумаюсь над переносом этого проекта на WPF например. Пока это не суть, мне бы разобраться с делегатами, событиями, свойствами и взаимосвязью между формами и классами...кто кого кому передает...итд. Спасибо.
    4 февраля 2013 г. 6:42
  • К ответу Алексея, мне собственно добавить нечего.

    4 февраля 2013 г. 13:00
  • У меня вопросы по коду. Они там в комментариях. Если не трудно мог бы кто-нибудь объяснить? Можно исправить существующие или дополнить, т.е. написать новые!?
    4 февраля 2013 г. 13:38
  • Качнул проект, открыл, глянул вполглаза, закрыл... :(

    SerializationController. Опять я вижу полуручную сериализацию. Зачем каждого человека по отдельности сохранять и читать в цикле? Я же на gdn приводил пример, как для всей коллекции целиком это делается одной строкой.

    ПыСы: потом, может, ещё посмотрю.

    4 февраля 2013 г. 15:28
  •         

    "Качнул проект, открыл, глянул вполглаза, закрыл... :(" — Что так? :)
    Давайте пока опустим SerializationController. Если не трудно, объясните пожалуйста, следующие конкретные конструкции, т.к. они мне не понятны...в большинстве своем события и делегаты. Сразу скажу, что перед тем как задавать вопрос, я  читал про это в rsdn.ru, msdn и Шилдте...

    ---Вопрос №1---
    Что означает здесь this ?

     ManageController controller;
    
            public FormPhoneBook()
            {
                InitializeComponent();
                controller = new ManageController(this);
            }



    ---Вопрос №2---

    Обработчик события нажатия по кнопке "Add New Contact"

    private void buttonAddNewContact_Click(object sender, EventArgs e)
            {
    
                NewItemForm newForm = new NewItemForm(true);
                if (newForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    if (AddClicked != null)
                        AddClicked(this, new AddPersonEventArgs(newForm.ItemName, newForm.ItemPhone, newForm.ItemAddress, newForm.ItemEmail, newForm.ItemBirthday));
                }
            }

    Тип события описан в классе:

    internal class AddPersonEventArgs : EventArgs
        {
    
            public AddPersonEventArgs(string name, string phone, string address, string email, DateTime birthday)
            {
    
                Name = name;
                Phone = phone;
                Address = address;
                Email = email;
                Birthday = birthday;
            }
    
            public string Name
            {
                get;
                private set;
            }
    
            public string Phone
            {
                get;
                private set;
            }
    
            public string Address
            {
                get;
                private set;
            }
    
    
            public string Email
            {
                get;
                private set;
            }
    
            public DateTime Birthday
            {
                get;
                private set;
            }
        }

    Подписчик на событие класс контроллера. И при наступлении события вызывается метод:

    public void SubscribeForm(FormPhoneBook form) {
    
              form.AddClicked += form_AddClicked;
            }
    
            void form_AddClicked(object sender, AddPersonEventArgs e) {
    
              Person p = new Person();
              p.Name = e.Name;
              p.Phone = e.Phone;
              p.Address = e.Address;
              p.Email = e.Email;
              p.Birthday = e.Birthday;
              this.people.Add(p);
              form.UpdateView(people);
            }

    Я правильно понимаю ?

    ---Вопрос №3---
    Зачем в классе New Item Form описываются еще раз свойства? Они же уже описаны в отдельном классе Person!? Который является моей моделью.  

      # region Properties
            public string ItemName
            {
                get
                {
                    return textBoxNewItemName.Text;
                }
            }
    
            public string ItemPhone
            {
                get
                {
                    return textBoxNewItemPhone.Text;
                }
            }
    
            public string ItemAddress
            {
                get
                {
                    return textBoxNewItemAddress.Text;
                }
            }
    
    
            public string ItemEmail
            {
                get
                {
                    return textBoxNewItemEmail.Text;
                }
            }
    
            public DateTime ItemBirthday
            {
                get
                {
                    return dateTimePickerNewItemBirthday.Value;
                }
            }
            #endregion


    Спасибо.


    4 февраля 2013 г. 19:56
  • ---Вопрос №1---

    Что означает здесь this ?

    controller = new ManageController(this);
    

    this - это ссылка на текущий экземпляр класса. В данном случае, так как код находится внутри реализации класса FormPhoneBook - это, соответственно, ссылка на экземпляр FormPhoneBook.

    Таким образом, код класса ManageController сможет использовать доступ к этому экземпляру. В частности, производится подписка на событие AddClicked.

    ---Вопрос №2---

    Обработчик события нажатия по кнопке "Add New Contact"

    ...

    Тип события описан в классе:

    ...

    Подписчик на событие класс контроллера. И при наступлении события вызывается метод:

    ...

    Я правильно понимаю ?

    Да.

    ---Вопрос №3---
    Зачем в классе New Item Form описываются еще раз свойства? Они же уже описаны в отдельном классе Person!? Который является моей моделью.

    В данном случае возвращаются не свойства Person, а свойства контролов формы. Делать можно так или иначе, вариантов много. Почему сделано именно так - вопрос не ко мне.

    5 февраля 2013 г. 13:29
  • ---Вопрос №3---

    Зачем в классе New Item Form описываются еще раз свойства? Они же уже описаны в отдельном классе Person!? Который является моей моделью.

    В данном случае возвращаются не свойства Person, а свойства контролов формы. Делать можно так или иначе, вариантов много. Почему сделано именно так - вопрос не ко мне.

    Kirill предлагал, когда приводил пример кода...автоматически реализуемые свойства. А как можно еще?
    5 февраля 2013 г. 14:07
  • Привет

    Главное для вас сейчас раз вы решили делать MVC в WinForm - это понимание самого паттерна MVC и для чего в предложенных решениях у формы вообще определялись какие-то свойства и класс AddPersonEventArgs.

    У вас есть модель - ваш класс Person, и представление - форма WinForms. А эти свойства выступают посредниками между моделью и представлением, для того чтобы не было жесткой зависимости между ними.


    Для связи [mail]

    6 февраля 2013 г. 8:45
  • Скажите, вот я по аналогии с добавлением контакта, пытаюсь создать событие удаления (и обновления) контакта из списка...и методы-обработчики, которые, собственно и будут удалять.

    Создаем событие типа DeletePErsonEventArgs:

    public event EventHandler<DeletePersonEventArgs> DeleteClicked;

    Двойным щелчком по кнопке "Delete Contact" студия создает обработчик события, он по сути, удалять объект не должен, т.к. у нас MVC, и следовательно он должен вызвать из контроллера метод, который удалит элемент!?

            private void buttonDeleteContact_Click(object sender, EventArgs e)
            {
                ????
            }

    Какой тип должен быть у этого события? Точно такой же как и у AddPersonEventArgs? Как описать тип этого события?

            internal class DeletePersonEventArgs : EventArgs
            {
    
                public DeletePersonEventArgs()
              {
    
                 ????
              }
             }

    В контроллере подписываемся на событие...

          public void SubscribeForm(FormPhoneBook form)
            {
    
                form.AddClicked += form_AddClicked;
                form.DeleteClicked += form_DeleteClicked;
            }

    И сам метод, который вызывается из класса контроллера, который обрабатывает событие!? т.е. каким - то образом обработчик события нажатия по кнопке buttonDeleteContact_Click должен вызвать непосредственно код, который удалит запись из List<Person> !?

    void form_DeleteClicked(object sender, DeletePersonEventArgs e)
    {
      if (listViewPeople.SelectedIndices.Count > 0)
                {
                    listViewPeople.Items.RemoveAt(listViewPeople.SelectedIndices[0]);
                }
    }



    10 февраля 2013 г. 19:26
  • Помогите, пожалуйста разобраться (тут солюшн http://webfile.ru/6371347 ) Что-то самостоятельно не получается :(

    1. Как описать типы событий удаления контакта и обновления?

    internal class DeletePersonEventArgs : EventArgs
    internal class UpdatePersonEventArgs : EventArgs

    По аналогии с типом добавления?

    internal class AddPersonEventArgs : EventArgs
     

    2. С обработчиками событий нажатия на кнопку Delete и Update соответственно.

    private void buttonDeleteContact_Click(object sender, EventArgs e)
    
    private void buttonUpdateContact_Click(object sender, EventArgs e)

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

    void form_DeleteClicked(object sender, DeletePersonEventArgs e)
    
    void form_UpdateClicked(object sender, UpdatePersonEventArgs e)

    Спасибо.

    11 февраля 2013 г. 17:12
  • Привет

    1. Вам из view нужно передать информацию в контроллер о выбранном в данный момент человеке.

    2. После этого контроллер удалит из модели этого человека

    3. Контроллер вызовете обновление view

    Т.е. в самом обработчике кнопки, вам нужно получить выделенный объект People из listview, потом обернуть его в DeletePersonEventArgs и вызывать событие аналогичное AddClicked, только которое будет содержать код удаление человека


    Для связи [mail]

    12 февраля 2013 г. 8:33
  • А как мне описать тип события ?

    internal class DeletePersonEventArgs : EventArgs

    Что должно быть в этом классе?

    12 февраля 2013 г. 9:16
  • Т.е. в самом обработчике кнопки, вам нужно получить выделенный объект People из listview, потом обернуть его в DeletePersonEventArgs и вызывать событие аналогичное AddClicked, только которое будет содержать код удаление человека

    А можно, если не трудно, привести пример кода? Что должно произойти из перечисленных пунктов я понял, а вот как это сделать в коде...не понятно :(

    Спасибо.



    12 февраля 2013 г. 9:29
  • Вот обработчик нажатия кнопки

            private void buttonDeleteContact_Click(object sender, EventArgs e)
            {
                if (DeleteClicked != null)
                    DeleteClicked(this, new DeletePersonEventArgs( ???  ));
            }

    вот кусок кода, который удаляет выбранный элемент из списка, и как я понимаю, этот код должен находиться в методе - обработчике в классе контроллера!?

    if (listViewPeople.SelectedIndices.Count > 0)
                {
                    listViewPeople.Items.RemoveAt(listViewPeople.SelectedIndices[0]);
                }
    но в таком случае получаю сообщение, что listViewPeople не определен в данном контексте. Т.е. нужно как-то сказать, что это  listViewPeople принадлежащий форме..типа form. listViewPeoplе...

    И с учетом

    "Т.е. в самом обработчике кнопки, вам нужно получить выделенный объект People из listview, потом обернуть его в DeletePersonEventArgs и вызывать событие аналогичное AddClicked, только которое будет содержать код удаление человека"

    нужно как-то так ?

    private void buttonDeleteContact_Click(object sender, EventArgs e) {

    	   if (listViewPeople.SelectedIndices.Count > 0)

    if (DeleteClicked != null) DeleteClicked(this, new DeletePersonEventArgs( ??? )); }

    а в методе обработчике только

                {
                    listViewPeople.Items.RemoveAt(listViewPeople.SelectedIndices[0]);
                }

    ???

    И как все-таки, описать тип события ?

    DeletePersonEventArgs

    12 февраля 2013 г. 19:25
  • В обработчике кнопки мы получаем элемент, который хотим удалить или его индекс:

     private void buttonDeleteContact_Click(object sender, EventArgs e)
            {
    	    if (listViewPeople.SelectedIndices.Count > 0)
                {
                    int index = listViewPeople.SelectedIndices[0];
        
                    if (DeleteClicked != null)
                         DeleteClicked(this, new DeletePersonEventArgs(index));
                }
            }
    Соответственно DeletePersonEventArgs должен принимать и хранить индекс:
    internal class DeletePersonEventArgs: EventArgs
        {
            public DeletePersonEventArgs(int index)
            {
    		Index = index;            
            }
            public int Index
            {
                get;
                private set;
            }
    }
    В самом обработчике события удаления:
    void form_DeleteClicked(object sender, DeletePersonEventArgs e)
        {         
              this.people.RemoteAt(e.Index);
              form.UpdateView(people);
        }




    Для связи [mail]

    13 февраля 2013 г. 8:20
  • Спасибо. Попробую сделать для Update.
    13 февраля 2013 г. 9:09
  • Для обновления, нам в обработчике кнопки, нужно так же получить индекс выделенного элемента
           
     private void buttonUpdateContact_Click(object sender, EventArgs e)
            {
                if (listViewPeople.SelectedIndices.Count > 0)
                {
                    int index = listViewPeople.SelectedIndices[0];
        
                    if (UpdateClicked != null)
                         UpdateClicked(this, new UpdatePersonEventArgs(index, newForm.ItemName, newForm.ItemPhone, newForm.ItemAddress, newForm.ItemEmail, newForm.ItemBirthday));
                }
            }

    Тогда UpdatePersonEventArgs должен по аналогии с Delete, принимать и хранить индекс, и все поля, котоорые определены в AddPersonEventArgs, чтобы иметь возможность перезаписать их!?


    internal class UpdatePersonEventArgs : EventArgs    {
            public UpdatePersonEventArgs (int index, string name, string phone, string address, string email, DateTime birthday)
            {            Index = index;
                Name = name;
                Phone = phone;
                Address = address;
                Email = email;
                Birthday = birthday;
            }     public int Index
            {
                get;
                private set;
            }
            public string Name
            {
                get;
                private set;
            }
            public string Phone
            {
                get;
                private set;
            }
            public string Address
            {
                get;
                private set;
            }
            public string Email
            {
                get;
                private set;
            }
            public DateTime Birthday
            {
                get;
                private set;
            }
        }
    Mетод-обработчик собития:
    void form_UpdateClicked(object sender, UpdatePersonEventArgs e)
            {
                Person p = new Person();
                p.Name = e.Name;
                p.Phone = e.Phone;
                p.Address = e.Address;
                p.Email = e.Email;
                p.Birthday = e.Birthday;
                this.people.Add(e.Index);
                form.UpdateView(people);
            }


    13 февраля 2013 г. 9:54
  • Все так, только вам нужно в form_UpdateClicked не добавлять человека в список, а получить его по индексу и изменить его свойства:

    Person p = this.people[e.Index];
    p.Name = e.Name;
    p.Phone = e.Phone;
    p.Address = e.Address;
    p.Email = e.Email;
    p.Birthday = e.Birthday;
    // отобразить изменения
    form.UpdateView(people);


    Для связи [mail]

    • Помечено в качестве ответа Andrey Langovoy 17 февраля 2013 г. 9:28
    • Снята пометка об ответе Abolmasov Dmitry 18 февраля 2013 г. 14:07
    13 февраля 2013 г. 11:07
  • И все-таки с обновлением контакта - не получается. При выборе контакта в лист вью и последующем нажатии на кнопку Update он просто исчезает!! :(

    Обработчик события нажатия по кнопке.

     private void buttonUpdateContact_Click(object sender, EventArgs e)
            {
                NewItemForm newForm = new NewItemForm(true);
                if (listViewPeople.SelectedIndices.Count > 0)
                {
                   int index = listViewPeople.SelectedIndices[0];
                    if (UpdateClicked != null)
                        UpdateClicked(this, new UpdatePersonEventArgs(index, newForm.ItemName, newForm.ItemPhone, newForm.ItemAddress, newForm.ItemEmail, newForm.ItemBirthday));
                }
            }

    у новой формы есть конструктор, который принимает булевскую переменную, кот. определяет новый контакт или существующий. В случае обновления он получается должен быть false ?

    bool NewItem = false;
    
            public NewItemForm(bool newItem)
             {
             }


    Код метода-обработчика

    void form_UpdateClicked(object sender, UpdatePersonEventArgs e)
            {
                Person p = this.people[e.Index];
                p.Name = e.Name;
                p.Phone = e.Phone;
                p.Address = e.Address;
                p.Email = e.Email;
                p.Birthday = e.Birthday;
                // отобразить изменения
                form.UpdateView(people);
            }


    Ну и тип события описанный в классе

    internal class UpdatePersonEventArgs : EventArgs
        {
            public UpdatePersonEventArgs(int index, string name, string phone, string address, string email, DateTime birthday)
            {
                Index = index;
                Name = name;
                Phone = phone;
                Address = address;
                Email = email;
                Birthday = birthday;
            }
            public int Index
            {
                get;
                private set;
            }
            public string Name
            {
                get;
                private set;
            }
            public string Phone
            {
                get;
                private set;
            }
            public string Address
            {
                get;
                private set;
            }
            public string Email
            {
                get;
                private set;
            }
            public DateTime Birthday
            {
                get;
                private set;
            }


    Чтобы в обработчиках события нажатия на кнопку переменная Index была видна, определил ее в самом начале

    internal partial class FormPhoneBook : Form
        {
    
            ManageController controller;
            int index;

    Подскажите, пожалуйста, в чем может быть проблема?

    Спасибо.

    13 февраля 2013 г. 17:59
  • Переписал код обработчика нажатия по кнопке таким образом

     private void buttonUpdateContact_Click(object sender, EventArgs e)
            {
                NewItemForm newForm = new NewItemForm(false);
                if (newForm.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    if (listViewPeople.SelectedIndices.Count > 0)
                    {
                        int index = listViewPeople.SelectedIndices[0];
                        if (UpdateClicked != null)
                            UpdateClicked(this, new UpdatePersonEventArgs(index, newForm.ItemName, newForm.ItemPhone, newForm.ItemAddress, newForm.ItemEmail, newForm.ItemBirthday));
                    }
                }
            }
    Теперь при выборе элемента в лист вью, он не исчезает, а открывается форма (добавления/редактирования) контакта, но она пустая. :(

    13 февраля 2013 г. 18:04