Làm cách nào tôi có thể áp dụng mẫu MVC cho ứng dụng C # WinForms?


11

Tôi là nhà phát triển C ++, người đã sử dụng mẫu MVC để thiết kế GUI kể từ đó.

Gần đây tôi muốn quay lại C # và tôi đã thiết lập một ứng dụng Windows Forms, nhưng bây giờ tôi hơi lạc lõng về cách đẩy nó sang cấu trúc tuân thủ MVC.

Những gì tôi hiện đang cố gắng làm là "khai báo" lớp tôi được trao cho WinForms dưới dạng Chế độ xem và thêm một lớp cho Mô hình và Trình điều khiển trong nền. Tuy nhiên, tôi không thực sự chắc chắn về cách tương tác với các sự kiện, như một lần bấm nút. Thông thường tôi sẽ chuyển hướng các sự kiện này đến bộ điều khiển và thực hiện một hành động trên Chế độ xem sau khi tôi hoàn thành.

Điều này cảm thấy khá không thỏa mãn trong chòm sao này. Ví dụ: nếu tôi muốn triển khai nút "Thoát", tôi sẽ phải chuyển hướng sự kiện từ Chế độ xem sang Trình điều khiển, cũng như triển khai một phương thức công khai bổ sung trong Chế độ xem mà sau đó có thể được gọi từ Trình điều khiển, trong khi tôi có thể chỉ cần gọi Đóng () từ Chế độ xem trong trường hợp đầu tiên.

Bạn có lời khuyên nào cho tôi không? Có phải sự hiểu biết của tôi về Windows Forms trong C # vẫn chưa đủ tốt để thử thực hiện MVC? Tôi có cho lớp biểu mẫu một vai trò sai không? Có phải MVC đơn giản là một kiến ​​trúc không phù hợp cho trường hợp sử dụng này?


1
Câu hỏi của Cựu ước. Nhưng tại sao WInforms? WPF có nghĩa là để thay thế Winforms và hỗ trợ MVC (Về mặt kỹ thuật MVVM). Mặc dù tôi sẽ nói rằng đường cong học tập WPF có thể dốc. (nhưng nếu bạn làm điều đó không tốt, bạn có thể làm cho mã WPF trông giống như Winforms)
Peter M

1
@PeterM: bởi vì thậm chí sau 10 năm WPF vẫn hút và vẫn chậm.
tên gì

3
Để diễn giải @ bình luận của whatsisname, WPF hướng đến các ứng dụng lớn hơn. Các ứng dụng nhỏ hơn có thể được phục vụ tốt hơn với Winforms vì Winforms đơn giản hơn nhiều. Tuy nhiên, nếu bạn muốn đưa ra lập luận đó, bạn cũng có thể đưa ra lập luận rằng ứng dụng Winforms của bạn đủ nhỏ để có thể không cần MVP. MVVM được đưa vào WPF. WPF có đồ họa dựa trên vectơ, do đó, nó không gặp phải vấn đề kích thước tương tự như Winforms. WPF rất có thể kết hợp (bạn có thể dễ dàng đặt các điều khiển bên trong các điều khiển khác) và nó có ràng buộc dữ liệu sát thủ. Có gì không thích?
Robert Harvey

3
@whatsisname WPF có thể hút, nhưng nó hút ít hơn Winforms cho bất cứ thứ gì trên và trên một chương trình đồ chơi
Peter M

2
Đối với các chương trình máy tính để bàn trong nhà, tôi muốn nói như vậy. Nhưng nhiều công ty thích các ứng dụng dựa trên trình duyệt cho hoạt động kinh doanh của họ, đơn giản vì không cần cài đặt.
Robert Harvey

Câu trả lời:


3

Thật trùng hợp, tôi đang làm việc trong một dự án WinForms được mô phỏng theo MVC. Tôi sẽ không gọi đây là một câu trả lời hoàn hảo, nhưng tôi sẽ giải thích thiết kế tổng thể của mình và hy vọng điều này có thể giúp bạn đưa ra ý kiến ​​của riêng mình.

Dựa trên bài đọc tôi đã làm trước khi bắt đầu dự án này, dường như không có cách "đúng" nào để thực hiện điều này. Tôi đã tuân theo các nguyên tắc thiết kế OOP và MVC đơn giản và phần còn lại là bản dùng thử và lỗi khi tôi phát triển một quy trình công việc.

Có phải MVC đơn giản là một kiến ​​trúc không phù hợp cho trường hợp sử dụng này?

Không ..? Không có đủ ngữ cảnh trong câu hỏi của bạn để cung cấp câu trả lời trực tiếp cho điều đó. Tại sao bạn sử dụng MVC ở nơi đầu tiên? Các yêu cầu không chức năng của dự án của bạn là gì? Dự án của bạn sẽ rất nặng UI? Bạn có quan tâm nhiều hơn về bảo mật và thay vào đó là một kiến ​​trúc lớp? Các thành phần chính của dự án của bạn là gì? Có lẽ mỗi thành phần cần một mẫu thiết kế khác nhau. Tìm hiểu lý do tại sao bạn muốn sử dụng mẫu thiết kế này ở nơi đầu tiên và bạn có thể trả lời câu hỏi của riêng bạn;)

Lý do của tôi khi sử dụng MVC: đó là một mẫu thiết kế khá đơn giản để hiểu theo ý kiến ​​của tôi và thiết kế của tôi dựa nhiều vào sự tương tác của người dùng. Cách MVC cho phép nhà phát triển tách biệt mối quan tâm là đủ cho ứng dụng của tôi. Điều này làm cho mã của tôi rất nhiều bảo trì và kiểm tra được.

Tôi cũng cho rằng tôi đang sử dụng nhiều hơn một thiết kế lai. Thông thường, khái niệm lý tưởng được trình bày trong công nghệ phần mềm không thực sự diễn ra trong thực tế. Bạn có thể sửa đổi thiết kế cho phù hợp với nhu cầu của dự án của bạn. Không cần phải bị cuốn vào những gì là đúng hay sai. Có những thực tiễn chung, nhưng các quy tắc luôn có thể bị bẻ cong hoặc phá vỡ miễn là bạn không tự bắn vào chân mình.

Việc triển khai của tôi bắt đầu với một thiết kế cấp cao cho tôi ý tưởng về những thành phần nào tôi sẽ cần. Tốt nhất của bạn để bắt đầu theo cách này và làm việc theo cách của bạn trong kiến ​​trúc. Đây là sơ đồ gói cho dự án (được tạo trong StarUML): nhập mô tả hình ảnh ở đây

Lưu ý mọi lớp đơn trừ lớp trình bày tùy thuộc vào Hệ thống nhắn tin. Đây là một "ngôn ngữ" phổ biến mà các lớp dưới và hệ thống phụ của các lớp đó sử dụng để giao tiếp với nhau. Trong trường hợp của tôi, đó là một phép liệt kê đơn giản dựa trên các thao tác có thể được thực hiện. Điều này đưa tôi đến điểm tiếp theo ...

Hãy nghĩ về các hoạt động hoặc các lệnh làm cơ sở cho việc thực hiện của bạn. Bạn muốn ứng dụng của bạn làm gì? Chia nó thành các hoạt động cơ bản nhất. Ví dụ: CreatProject, WriteNotes, SaveProject, LoadProject, v.v. GUI (hoặc các lớp Form) sẽ có một số sự kiện xảy ra (như nhấn nút). Mỗi hoạt động có một phương thức điều khiển liên quan đến nó. Trong trường hợp này, một cái gì đó như Thoát là quá đơn giản. Ứng dụng có thể được đóng lại từ lớp Form. Nhưng giả sử tôi muốn duy trì một số dữ liệu ứng dụng vào một tệp trước? Tôi sẽ gọi phương thức "Lưu" từ lớp trình điều khiển tương ứng trong phương thức nhấn nút của tôi.

Từ đó, bộ điều khiển sẽ gọi tập hợp hoạt động chính xác từ các lớp Service. Các lớp dịch vụ trong ứng dụng của tôi hoạt động như một giao diện cho lớp miền. Họ sẽ xác nhận đầu vào nhận được từ lệnh gọi phương thức điều khiển (và do đó từ GUI) và thao tác mô hình dữ liệu.

Khi xác thực và thao tác đối tượng tương ứng hoàn tất, phương thức dịch vụ sẽ trả về mã thông báo cho bộ điều khiển. Ví dụ , MessageCodes.SaveSuccess. Cả hai lớp điều khiển và dịch vụ đều dựa trên các đối tượng miền và / hoặc tập hợp các hoạt động chung có thể được nhóm lại với nhau.

Ví dụ: FileMenuController(hoạt động: NewProject, SaveProject, LoadProject) -> ProjectServices(CreatProject, PersistProjectToFile, LoadProjectFromFile). Trường hợp Projectsẽ là một lớp miền trong mô hình dữ liệu của bạn. Các lớp Trình điều khiển và Dịch vụ trong trường hợp của tôi là các lớp không thể thực hiện được với các phương thức tĩnh.

Sau đó, bộ điều khiển nhận ra thao tác là hoàn thành un / thành công. Bây giờ, bộ điều khiển có hệ thống nhắn tin riêng mà nó sử dụng để tương tác với lớp trình bày, do đó phụ thuộc gấp đôi giữa các lớp Dịch vụ và Bản trình bày. Trong trường hợp này, một lớp được gọi ViewStatetrong ViewModelsgói luôn được bộ điều khiển trả về GUI. Trạng thái này chứa thông tin như: " trạng thái bạn đã cố gắng đặt ứng dụng có hiệu lực không? ", " Một thông báo có thể đọc được của con người về hoạt động bạn đã cố thực hiện và tại sao nó lại hoặc không thành công (thông báo lỗi) " và một ViewModellớp.

Các ViewModellớp chứa dữ liệu có liên quan từ các lớp miền GUI sẽ sử dụng để cập nhật xem. Các mô hình khung nhìn này trông giống như các lớp miền nhưng trong trường hợp của tôi, tôi đã sử dụng các đối tượng rất mỏng . Về cơ bản, họ không có nhiều hành vi, chỉ chuyển tiếp thông tin về trạng thái cấp thấp hơn của ứng dụng. Nói cách khác, tôi KHÔNG BAO GIỜ sẽ tặng các lớp miền của mình cho lớp trình bày. Đây cũng là lý do tại sao ControllersServicescác gói chia lớp dịch vụ thành hai phần. Bộ điều khiển sẽ không bao giờ xử lý các lớp miền hoặc xác nhận trạng thái của chúng. Chúng chỉ hoạt động như một ranh giới chuyển đổi dữ liệu liên quan GUI thành dữ liệu liên quan đến miền mà các dịch vụ có thể sử dụng và ngược lại. Bao gồm logic dịch vụ trong bộ điều khiển sẽ dẫn đến rất béo bộ điều khiển, khó bảo trì hơn.

Tôi hy vọng điều này cung cấp cho bạn một điểm khởi đầu.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.