Як я можу застосувати шаблон MVC до програми C # WinForms?


11

Я розробник C ++, який з тих пір використовує шаблон MVC для проектування графічних інтерфейсів.

Нещодавно я хотів повернутися в C #, і я створив додаток Windows Forms, але зараз я трохи розгублений, як перенести його на структуру, сумісну з MVC.

Наразі я намагаюся зробити «оголосити» клас, який я даю для WinForms як перегляд, і додати клас для моделі та контролера у фоновому режимі. Однак я не дуже впевнений, як взаємодіяти з подіями, як-от натискання кнопки. Зазвичай я переспрямовую ці події до контролера та виконую дію на Перегляд, як тільки я закінчу.

В цьому сузір'ї це відчуває себе досить незадовільно. Наприклад, якщо я хотів реалізувати кнопку «Вихід», мені доведеться перенаправляти подію з Погляду на контролер, а також реалізувати додатковий відкритий метод у своєму представленні, який потім можна викликати з Контролера, тоді як я міг просто зателефонувати Close () з виду Першої інстанції.

Ви маєте поради для мене? Чи моє розуміння форм Windows в C # просто недостатньо, щоб спробувати впровадження MVC? Чи я надаю класу форм неправильну роль? Чи просто MVC невідповідна архітектура для цього випадку використання?


1
ОТ питання. Але чому WInforms? WPF повинен був замінити Winforms та підтримувати MVC (Ну технічно MVVM). Хоча я скажу, що крива навчання WPF може бути крутою. (але якщо це зробити погано, ви можете зробити код WPF схожим на Winforms)
Peter M

1
@PeterM: адже навіть через 10 років WPF смокче і все ще повільно.
whatsisname

3
Якщо перефразовувати коментар @ whatsisname, WPF орієнтований на більші програми. Менші програми, можливо, краще обслуговуватимуться з Winforms, тому що Winforms, можливо, простіше. Однак, якщо ви хочете зробити цей аргумент, ви також можете зробити аргумент про те, що ваша програма Winforms є достатньо малою, де вона, мабуть, не потребує MVP. MVVM випікається у WPF. WPF має векторну графіку, тому він не зазнає тих самих проблем із розміщенням, що і Winforms. WPF дуже зручний для компонування (ви можете легко поставити елементи управління в інші елементи управління), і він має прив'язувати дані вбивці. Що не подобається?
Роберт Харві

3
@whatsisname WPF може смоктати, але він висмоктує набагато менше, ніж Winforms за будь-яку програму іграшок і вище
Пітер М,

2
Для внутрішніх настільних програм я б сказав так. Але багато компаній віддають перевагу браузерним програмам для своєї господарської діяльності просто тому, що не потрібно встановлення.
Роберт Харві

Відповіді:


3

Випадково я працюю над проектом WinForms, який є візерунком після MVC. Я б не назвав це ідеальною відповіддю, але я поясню свій загальний дизайн і, сподіваюся, це допоможе вам придумати свій власний.

На основі прочитання, яке я зробив перед початком цього проекту, здається, що немає "правильного" способу його втілення. Я дотримувався простих принципів проектування OOP та MVC, а решта - пробні помилки, коли я розробляв робочий процес.

Чи просто MVC невідповідна архітектура для цього випадку використання?

Ні ..? У вашому запитанні недостатньо контексту, щоб дати пряму відповідь на це. Чому ви в першу чергу використовуєте MVC? Які нефункціональні вимоги вашого проекту? Ваш проект буде дуже важким у користувальницькому інтерфейсі? Ви більше піклуєтесь про безпеку та скоріше шарувату архітектуру? Які основні компоненти вашого проекту? Можливо, для кожного компонента потрібна інша модель дизайну. Дізнайтеся, чому ви хочете використовувати цей шаблон дизайну в першу чергу, і ви можете відповісти на власне запитання;)

Моя причина використання MVC: його досить проста модель дизайну, яку можна зрозуміти, на мій погляд, і моя конструкція ґрунтується на взаємодії з користувачем. Те, як MVC дозволяє розробнику окремо висловлювати проблеми, є достатнім і для моєї заявки. Це робить мій код набагато більш ретельним і перевіреним.

Я також припускаю, що я використовую більше гібридного дизайну. Зазвичай ідеальна концепція, представлена ​​в інженерії програмного забезпечення, насправді не реалізується на практиці. Ви можете змінити дизайн відповідно до потреб вашого проекту. Не потрібно зациклюватися на тому, що правильно чи неправильно. Існують загальні практики, але правила завжди можна зігнути або порушити до тих пір, поки ви не стріляєте собі в ногу.

Моя реалізація почалася з дизайну високого рівня, який дав мені уявлення про те, які компоненти мені знадобляться. Найкраще починати саме так і працювати в напрямку архітектури. Ось пакетна схема проекту (створеного в StarUML): введіть тут опис зображення

Зауважте, що кожен шар, крім шару презентації, залежить від системи обміну повідомленнями. Це загальна "мова", яку нижні шари та підсистеми цих шарів використовують для спілкування один з одним. У моєму випадку це було просте перерахування на основі операцій, які можна виконати. Що підводить мене до наступного моменту ...

Подумайте про операції або команди як основу для вашої реалізації. Що ви хочете робити у вашій заяві? Розбийте його на найбільш фундаментальні операції. Наприклад: CreateProject, WriteNotes, SaveProject, LoadProject і т. Д. У графічному інтерфейсі (або в класах форм) відбудеться деяка подія (наприклад, натискання кнопки). Кожна операція має пов'язаний з нею метод контролера. У цьому випадку щось на кшталт Виходу занадто просто. Додаток можна просто закрити з класу Form. Але припустимо, що я хотів спочатку зберегти деякі дані програми у файлі? Я зателефоную методу "Зберегти" з відповідного класу контролера в межах мого методу натискання кнопки.

Звідти контролер викличе правильний набір операцій із класів Сервісу. Класи обслуговування в моїй програмі виконують функції інтерфейсу до доменного рівня. Вони перевірять вхід, отриманий від виклику методу контролера (і, таким чином, від GUI), і маніпулюють моделлю даних.

Після завершення перевірки та маніпуляції відповідним об'єктом сервісний метод поверне код повідомлення в контролер. Наприклад, MessageCodes.SaveSuccess. І контролер, і класи обслуговування базувалися на об'єктах домену та / або на загальному наборі операцій, які можна об'єднати.

Наприклад: FileMenuController(операції: NewProject, SaveProject, LoadProject) -> ProjectServices(CreateProject, PersistProjectToFile, LoadProjectFromFile). Де Projectбув би доменний клас у вашій моделі даних. Класи контролерів та сервісу в моєму випадку були немоментальними класами статичними методами.

Потім контролер визнає операцію завершеною un / успішною. Тепер контролер має власну систему обміну повідомленнями, яку він використовує для взаємодії з презентаційним шаром, отже, подвійна залежність між рівнями Сервіс та Презентація. У цьому випадку клас, викликаний ViewStateу ViewModelsпакеті, завжди повертається до GUI контролером. Цей стан містить інформацію на зразок: " це стан, в якому ви намагалися поставити програму дійсною? ", " Зрозуміле для людини повідомлення про операцію, яку ви намагалися виконати, і чому це було чи не було успішним (повідомлення про помилку) " та ViewModelклас.

ViewModelКлас містить відповідні дані з області шару , що графічний інтерфейс буде використовувати для поновлення виду. Ці моделі подання виглядають як доменні класи, але в моєму випадку я використовував дуже худі об'єкти. В основному вони практично не мають поведінки, просто передають інформацію про стан програми нижчого рівня. Іншими словами, я НІКОЛИ не збираюся роздавати свої доменні класи презентаційному шару. Ось чому Controllersі Servicesпакети розділяють сервісний шар на дві частини. Контролери ніколи не будуть обробляти доменні класи або перевіряти їх стан. Вони просто виконують функцію кордону, що перетворює відповідні дані графічного інтерфейсу у дані, що стосуються домену, які сервіси можуть використовувати, і навпаки. Включення логіки обслуговування в контролер призведе до дуже жирності контролери, які важче підтримувати.

Сподіваюся, це дає тобі вихідну точку.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.