Download as pdf or txt
Download as pdf or txt
You are on page 1of 17

Thiết kế giao diện cho winforms – Series Giải

pháp winforms (2)


Đăng bởi Trọng Nhân - 12/05/2019

Thiết kế giao diện chắc chắn là phần hấp dẫn nhất đối với các bạn mới bắt đầu làm việc
với winform, đặc biệt các bạn mới chuyển từ console sang. Tuy vậy, không phải ai cũng
biết cách phát huy các khả năng hỗ trợ của winform khi thiết kế giao diện.

Như đã phân tích trong phần 1 – các lỗi thường gặp trong lập trình winform – các bạn
thường làm thủ công, mất nhiều công sức, dễ gặp lỗi. Việc thay đổi giao diện chương
trình chắc chắn là một ác mộng!

Trong bài viết này, tôi sẽ giúp bạn tránh hết những phiền toái đó.

NỘI DUNG CỦA BÀI [ Ẩn ]


1. Về mô hình kiến trúc UI trong thiết kế giao diện winform
1.1. Mô hình kiến trúc UI là gì?
1.2. Mô hình UI cho giao diện winform
1.3. Mô hình UI tự tạo cho winform
2. Thiết kế giao diện winform sử dụng Data Sources và BindingSource
2.1. Chuẩn bị cấu trúc mã nguồn
2.2. Tạo Data Sources cho project
2.3. Thiết kế giao diện form Contact
2.4. Một số lưu ý trong thiết kế giao diện cho winform
3. Viết code xử lý cho các chức năng chính
3.1. Lớp ContactsViewModel
3.2. Đọc/ghi dữ liệu từ file
3.3. Thay thế thanh Navigator
3.4. Thiết kế giao diện Master – details trong winform
3.5. Bind trực tiếp giao diện với VM
4. Một số nhận xét
5. Kết phần
5.1. Tải mã nguồn Giải pháp winforms (2): áp dụng mô hình kiến trúc UI

Loạt bài “Các giải pháp dành cho lập trình winform”:

Phần 1 – Lỗi thường gặp trong lập trình winforms

Phần 2 – Thiết kế giao diện với Data Sources và BindingSource

Phần 3 – Phân chia code thành module sử dụng Interface

Phần 4 – Sử dụng thư viện DevExpress cho winforms

Phần 5 – Sử dụng Data Binding

Phần 6 – Sử dụng Entity Framework

Về mô hình kiến trúc UI trong thiết kế giao diện winform

Mô hình kiến trúc UI là gì?


Mô hình kiến trúc UI là một vấn đề tương đối “cao cấp” mà ít bạn biết tới khi học lập
Mô hình kiến trúc UI là một vấn đề tương đối “cao cấp” mà ít bạn biết tới khi học lập
20
trình. Tuy nhiên, nó không thực sự quá xa lạ. Bạn hẳn đã nghe ở đâu đó về “mô hình
MVC” trong phát triển ứng dụng web cũng như một số framework xây dựng theo mô 
hình này. MVC chính là một kiến trúc UI rất thông dụng dành cho giao diện người dùng.
Ngoài MVC còn có nhiều mô hình khác được sử dụng với những công nghệ nhất định.

Các mô hình kiến trúc UI có vai trò rất quan trọng khi xây dựng các project lớn. Nó giúp
phân chia code ra các thành phần (module) một cách logic, tiện lợi cho việc sửa đổi và
bảo trì về sau.

Đại thể, các mô hình kiểu này hướng tới tuân thủ nguyên lý SoC (Separation of
Concern). Ý tưởng cơ bản của SoC là phân chia code ra các thành phần tương đối độc lập
theo nhiệm vụ cụ thể để một chương trình có tính modular.

Các mô hình UI hướng tới phân chia client UI ra làm giao diện (view), logic, dữ liệu
(model). Tùy vào sự tương tác giữa các thành phần này sẽ tạo ra các mẫu kiến trúc khác
nhau.

Mô hình UI cho giao diện winform


Vậy đối với windows forms thì sao? Bạn có cần đến một mô hình UI khi thiết kế giao diện
winform? Bạn có thể tự tạo một mô hình UI riêng hay phải dùng các mô hình đã có?

Windows Forms không được xây dựng cùng với một mô hình kiến trúc UI nào từ đầu.
Trong khi các công nghệ mới hơn như WPF có riêng một mô hình kiến trúc UI gọi là
MVVM (Model-View-ViewModel).

Khi cần đến SoC cho UI trong winform, người ta thường áp dụng mô hình MVP ( Model-
View-Presenter, biến thể supervising controller hoặc passive view). Khi MVVM ra đời, do
winforms cũng hỗ trợ khá tốt data binding, mô hình này cũng được áp dụng trở lại cho
winforms.

Tuy nhiên, cả MVVM và MVP đều rất khó thực thi cho winforms. Vì vậy, nếu không có
những nhu cầu đặc biệt (như testability) thì không nhất thiết phải áp dụng các mô hình
này.

Mô hình UI tự tạo cho winform


Để thuận lợi cho làm những project vừa và nhỏ, chúng ta có thể tự đưa ra mô hình riêng.

Giải pháp của chúng ta dựa trên kết hợp mô hình MVVM và MVP nhưng đơn giản hóa và
cải biên cho windows forms.

Trong mô hình này, project winform sẽ được chia làm 3 phần: View – ViewModel –
Model.

View là cái người dùng nhìn thấy, cũng chính là lớp Form mà bạn đang xây dựng. Trên
Form đặt các điều khiển khác nhau để tương tác với người dùng. Cái này hoàn toàn quen
thuộc với bạn. Tuy nhiên, để phù hợp với mô hình UI này, chúng ta phải vận dụng các kỹ
thuật thiết kế nhằm khai thác khả năng Databinding Nếu không dữ liệu sẽ khó đồng bộ
thuật thiết kế nhằm khai thác khả năng Databinding. Nếu không, dữ liệu sẽ khó đồng bộ
20
giữa ViewModel và View.

ViewModel chứa toàn bộ các logic để chuẩn bị dữ liệu cho View. Tất cả dữ liệu View
phải trả về ViewModel để xử lý. Tất cả sự kiện phát sinh trên View (ví dụ, người dùng
bấm nút trên Form) cũng được delegate về ViewModel để xử lý.

Điều này cũng có nghĩa là trong lớp Form bạn đang xây dựng sẽ không có phương thức
xử lý sự kiện nào. Nó sẽ hoàn toàn khác biệt với những gì bạn đã quen làm trước đây: xử
lý sự kiện của điều khiển ngay trong Form.

Chúng ta sẽ tự tạo ra một cơ chế gọi là “Command” để ViewModel có thể tương tác với
View, ví dụ, phát lệnh mở Form mới, mở hộp thoại.

Model là phần dữ liệu được lưu trữ ở đâu đó, có thể trong bộ nhớ, trong file hoặc ở cơ sở
dữ liệu. ViewModel sẽ làm nhiệm vụ lấy dữ liệu này, biến đổi nó theo logic định sẵn,
thông qua cơ chế Data Binding để đồng bộ dữ liệu với View. ViewModel phải thực hiện đủ
các thao tác CRUD với dữ liệu.

Để View có thể hiển thị dữ liệu, nó phải biết đến cấu trúc (schema) của Model. Tuy
nhiên, View không cần quan tâm đến dữ liệu.

Nghe rất lằng nhằng phải không ạ? Tôi cá là bạn không hiểu mấy đâu, và cũng bắt đầu
nghi ngờ, liệu có nên đọc tiếp không. Nó bắt đầu xa lạ rồi.

Nhưng bạn đừng lo, có cả series 5 bài liên tục để giúp bạn. Hãy đi cùng chúng tôi đến
cuối, bạn sẽ thấy thực ra nó rất đơn giản. Đơn giản hơn nhiều so với những gì mô tả ở
đây.

Đến khi hiểu nó, bạn sẽ thấy nó vô cùng hữu ích. Đảm bảo rằng nếu bạn làm đề tài/đồ
án mà sử dụng những giải pháp ở loạt bài này, bạn sẽ tiết kiệm được một nửa thời gian.

Thật đấy!

Để hiểu mô hình này, chúng ta bắt đầu trước bằng thực hiện ví dụ minh họa (đã bắt đầu
từ bài trước).

Thiết kế giao diện winform sử dụng Data Sources và


BindingSource

Chuẩn bị cấu trúc mã nguồn


Bước 1. Trước hết xóa bỏ Form1 được tạo cùng project App. Thêm hai form mới vào
project, đặt tên lần lượt là Contacts và Detail.

Contacts sẽ hiển thị danh sách liên hệ của danh bạ. Detail sẽ hiển thị chi tiết về contact
đang được chọn.

Bước 2. Mở file Program.cs và sửa dòng Application.Run(new Form1()); thành


ước ở e og a cs à sửa dò g pp ( ()); t à
20
Application.Run(new Contacts()); , do chúng ta đã xóa bỏ Form1. Giờ Contacts trở
thành form khởi động của ứng dụng.

Bước 3. Thêm thư mục ViewModels vào project này. Trong thư mục ViewModels tạo một
class mới có tên ContactsViewModel (file ContactsViewModel.cs).

Bước 4. Thiết lập để App trở thành startup project (project sẽ chạy khi ấn F5).

Cấu trúc App winforms project

Tạo Data Sources cho project


Khi thiết kế giao diện, để tận dụng được khả năng data binding của lập trình winforms,
chúng ta cần dùng một công cụ gọi là Data Sources cùng với class BindingSource.

Bước 1. Mở tab Data Sources (View => Other Windows => Data Sources, hoặc
Shift+Alt+D), bấm nút link Add New Data Source.

Bước 2. Trong cửa sổ Data Source Configuration Wizard, bước Choose a Data Source
Type chọn Object và Next.

Bước 3. Trong mục Select the Data Objects mở rộng node Models => Models và chọn
Contact. Ấn Finish để kết thúc. Nếu ở bước này không nhìn thấy node Models thì đóng
cửa sổ này lại và Build project Models. Sau đó lặp lại từ bước 1.
20

Các bước tạo Data Source cho project

Lưu ý rằng tab Data Sources thể hiện nội dung khác nhau tùy vào project nào đang lựa
chọn.
20

Data Sources thay đổi tùy project

Các file tạo ra cho Data Source

Thiết kế giao diện form Contact


Sử dụng SplitContainer và GroupBox để tạo ra cái khung cho giao diện như sau
20
Khung Contacts form

Hi vọng bạn đã biết vai trò và cách sử dụng của SplitContainer và GroupBox.

Bước 1. Chuyển Contact Data Source thành DataGridView

Bước 2. Kéo – thả Contact DataGridView vào giao diện

Bước 3. Chuyển Contact Data Source thành Details

Bước 4. Kéo – thả Contact Details vào Detail GroupBox; Kéo Emails và Phones lần lượt
thả vào hai panel bên dưới Detail GroupBox

Thao tác xây dựng giao diện Contacts

Chúng ta nhanh chóng thu được một giao diện ứng dụng như sau
20
Giao diện Contacts form sau khi hoàn thành


Đến đây bạn có thể tùy ý tinh chỉnh để giao diện nhìn “chuyên nghiệp” hơn.

Lưu ý đổi thuộc tính Enabled của contactBindingNavigatorSaveItem thành True (mặc
định là False). Đây là nút Save trên thanh navigator.

Một số lưu ý trong thiết kế giao diện cho winform


Các bạn có thể thấy, nhờ Data Source mà quá trình thiết kế giao diện đã đơn giản hơn
rất nhiều: bạn không cần kéo thả thủ công từng điều khiển lên form nữa.

Data Source đã cho winforms biết thông tin về dữ liệu (metadata hoặc schema). Từ dữ
liệu meta winforms tự xác định loại điều khiển nào cần dùng để hiển thị trường dữ liệu
tương ứng.

Dĩ nhiên, bạn hoàn toàn có thể tự kéo thả các điều khiển và sau đó tự điều chỉnh data
binding cho chúng. Nhưng nếu đã có hỗ trợ tự động thì tội gì làm thủ công! Hãy tự xem
cách bind các điều khiển này trong nhóm Data => DataBindings của cửa sổ Properties
(F4).

Tất cả các điều khiển kéo thả lên form đều đã được được liên kết với dữ liệu (data bound
controls). Nguồn dữ liệu chung của tất cả các điều khiển này là object
contactBindingSource . Đây là một object của lớp BindingSource.

BindingSource là một lớp trung gian đặc biệt đóng vai trò nguồn dữ liệu và làm data
binding trong lập trình winforms đơn giản và hiệu quả hơn. Lớp này giúp đồng bộ hóa dữ
liệu giữa tất cả các điều khiển kết nối tới nó. Khi có thay đổi về dữ liệu, BindingSource tự
phát đi các thông báo để cập nhật lại điều khiển. Lớp này cũng có nhiều sự kiện khác
nhau liên quan đến sự biến đổi giá trị của dữ liệu.

Viết code xử lý cho các chức năng chính


Ở trên chúng ta đã thiết kế xong giao diện nhưng chưa thực hiện được gì khác. Theo mô
hình UI tự tạo, tất cả logic và tính toán phải được thực hiện trong một class khác.

Lớp ContactsViewModel
Ở giai đoạn chuẩn bị bên trên bạn đã tạo ra lớp ContactsViewModel. Đây là class chịu
trách nhiệm xử lý tất cả các loại logic liên quan đến dữ liệu và tính toán phát sinh trên
giao diện, cũng như xử lý sự kiện từ các điều khiển.

Đối với bài toán này, một số thao tác sau cần xử lý:
20


Tải dữ liệu từ file (hoặc cơ sở dữ liệu)

Lưu dữ liệu trở lại file (hoặc cơ sở dữ liệu)

Xóa bản ghi đang được chọn

Cập nhật bản ghi đang được lựa chọn

Thêm một bản ghi contact mới

Khi chọn một contact bất kỳ sẽ thực hiện được các yêu cầu sau:

Hiển thị các thông tin chi tiết của contact đó trên cùng form hoặc trên một form riêng

Hiển thị danh sách email và số điện thoại

Thực hiện được các thao tác CRUD đối với danh sách email và điện thoại

Đọc/ghi dữ liệu từ file


Viết code cho lớp ContactsViewModel như sau

1. using System.Collections.Generic;
2. using System.IO;
3. using System.Runtime.Serialization.Formatters.Binary;
4. using System.Windows.Forms;
5. using Models;
6.
7. namespace App.ViewModels
8. {
9. public class ContactsViewModel
10. {
11. public BindingSource ContactBindingSource { get; set; }
12.
13. public void Load()
14. {
15. List<Contact> contacts;
16. var formatter = new BinaryFormatter();
17.
18. if (!File.Exists("data.dat"))
19. {
20. contacts = new List<Contact>();
21. var stream = File.Create("data.dat");
22. formatter.Serialize(stream, contacts);
23. stream.Close();
24. }
25. else
26. {
27. using (var stream = File.OpenRead("data.dat"))
28. {
29. contacts = formatter.Deserialize(stream) as List<Contact>;
30. }
31. }
32.
33. ContactBindingSource.ResetBindings(false);
34. ContactBindingSource.DataSource = contacts;
35. }
36.
37. public void Save()
38. {
39. using (var stream = File.OpenWrite("data.dat"))
40. {
41. var formatter = new BinaryFormatter();
42. formatter.Serialize(stream, ContactBindingSource.DataSource);
43. }
44. }
45. }
46. }

Mở d ủ f C t t (F7) à d hư
Mở code của form Contacts (F7) và code như sau:
20

1.
2.
using System.Windows.Forms; 
3. namespace App
4. {
5. public partial class Contacts : Form
6. {
7. private ViewModels.ContactsViewModel _vm = new ViewModels.ContactsViewModel()
8.
9. public Contacts()
10. {
11. InitializeComponent();
12.
13. _vm.ContactBindingSource = contactBindingSource;
14. contactBindingNavigatorSaveItem.Click += delegate { _vm.Save(); };
15. Load += delegate { _vm.Load(); };
16. }
17. }
18. }

Dịch và chạy thử chương trình. Nhập vào một số dữ liệu và ấn nút Save. Đóng chương
trình và chạy lại để xem dữ liệu có được lưu và tải lên không.

Chương trình quản lý danh bạ

Các bạn có thể thấy, chúng ta đã rất nhanh chóng tạo ra một chương trình hoạt động.
Hầu hết các hoạt động xử lý CRUD cơ bản đã được Binding Navigator và Binding Source
hỗ trợ. Chúng ta chỉ cần xử lý chính cho việc đọc/ghi dữ liệu với file.

Thay thế thanh Navigator


Thanh công cụ Navigator là một điều khiển rất hữu dụng và tiện lợi khi sử dụng cùng
BindingSource. Tuy nhiên, không phải ai cũng thích thanh công cụ này. Trong phần này
chúng ta sẽ tự thêm một thanh công cụ khác có chức năng tương tự.

Trước hết kéo thả một Panel vào và thiết lập thuộc tính Dock thành Bottom. Đặt lên
Panel một số Button rồi đặt thuộc tính Text và Name như hình dưới đây.
20

Tạo Panel điều khiển mới

Bổ sung code sau vào ContactsViewModel

1. public void New()


2. {
3. var contact = ContactBindingSource.AddNew() as Contact;
4. contact.DateOfBirth = DateTime.Now;
5. contact.ContactName = "new conatct";
6. }
7. public void Delete() => ContactBindingSource.RemoveCurrent();
8. public void First() => ContactBindingSource.MoveFirst();
9. public void Last() => ContactBindingSource.MoveLast();
10. public void Previous() => ContactBindingSource.MovePrevious();
11. public void Next() => ContactBindingSource.MoveNext();

Sửa code behind của Contacts như sau

1. using System.Windows.Forms;
2.
3. namespace App
4. {
5. public partial class Contacts : Form
6. {
7. private ViewModels.ContactsViewModel _vm = new ViewModels.ContactsViewModel()
8.
9. public Contacts()
10. {
11. InitializeComponent();
12.
13. _vm.ContactBindingSource = contactBindingSource;
14.
15. Load += delegate { _vm.Load(); };
16.
17. buttonNew.Click += delegate { _vm.New(); };
18. buttonDelete.Click += delegate { _vm.Delete(); };
19. buttonSave.Click += delegate { _vm.Save(); };
20. buttonFirst.Click += delegate { _vm.First(); };
21. buttonLast.Click += delegate { _vm.Last(); };
22. buttonPrevious.Click += delegate { _vm.Previous(); };
23. buttonNext.Click += delegate { _vm.Next(); };
24. }
25. }
26. }
20
Dịch và chạy thử ứng dụng xem các button mới hoạt động ra sao.

Thiết kế giao diện Master – details trong winform


Master-details là một loại view được sử dụng đặc biệt nhiều trong ứng dụng quản lý
(Line-of-Business, LOB). Loại view này thể hiện quan hệ 1-n về dữ liệu. Như trong bài
toán của chúng ta, 1 contact chứa nhiều email và nhiều phone.

Ứng dụng của chúng ta đã sử dụng loại view này ngay từ đầu. Mỗi khi chọn một contact
bất kỳ sẽ hiển thị thông tin chi tiết, danh sách email, danh sách phone.

Nhờ BindingSource, master-detail view được thực hiện một cách đơn giản. Trên form
Contacts , emailsDataGridView có DataSource là emailsBindingSource . Bản thân
emailsBindingSource lại có DataSource là contactBindingSource . Thuộc tính
DataMember của của emailsBindingSource nhận giá trị Emails , vốn là tên trường
tương ứng của Contact nơi chứa danh sách email.

Hãy cùng thêm một số chức năng để tương tác với danh sách email và phone.

Trên thanh điều khiển mới thêm một số nút bấm như hình dưới đây

Thêm nút xử lý email và phone

Viết thêm code sau vào cuối ContactsViewModel:

1. public BindingSource EmailBindingSource { get; set; }


2. public BindingSource PhoneBindingSource { get; set; }
3. public void NewEmail()
4. {
5. var email = EmailBindingSource.AddNew() as Email;
6. email.EmailAddress = "@gmail.com";
7. }
8. public void DeleteEmail() => EmailBindingSource.RemoveCurrent();
9. public void NewPhone()
10. {
11. var phone = PhoneBindingSource.AddNew() as Phone;
12. phone.Number = "(+84) ";
13 }
13. }
2014. public void DeletePhone() => PhoneBindingSource.RemoveCurrent();

Điều chỉnh code behind của Contacts form: 

1. using System.Windows.Forms;
2.
3. namespace App
4. {
5. public partial class Contacts : Form
6. {
7. private ViewModels.ContactsViewModel _vm = new ViewModels.ContactsViewModel()
8.
9. public Contacts()
10. {
11. InitializeComponent();
12.
13. _vm.ContactBindingSource = contactBindingSource;
14. _vm.EmailBindingSource = emailsBindingSource;
15. _vm.PhoneBindingSource = phonesBindingSource;
16.
17. Load += delegate { _vm.Load(); };
18.
19. buttonNew.Click += delegate { _vm.New(); };
20. buttonDelete.Click += delegate { _vm.Delete(); };
21. buttonSave.Click += delegate { _vm.Save(); };
22. buttonFirst.Click += delegate { _vm.First(); };
23. buttonLast.Click += delegate { _vm.Last(); };
24. buttonPrevious.Click += delegate { _vm.Previous(); };
25. buttonNext.Click += delegate { _vm.Next(); };
26.
27. buttonNewEmail.Click += delegate { _vm.NewEmail(); };
28. buttonDeleteEmail.Click += delegate { _vm.DeleteEmail(); };
29. buttonNewPhone.Click += delegate { _vm.NewPhone(); };
30. buttonDeletePhone.Click += delegate { _vm.DeletePhone(); };
31. }
32. }
33. }

Dịch và chạy thử chương trình với các chức năng mới

Chương trình với các chức năng mới

Bind trực tiếp giao diện với VM


Trong các phần trên chúng ta đều bind gián tiếp các điều khiển với BindingSource. Giờ
giả sử chúng ta muốn rằng khi chọn bất kỳ contact nào, tên của nó sẽ xuất hiện trên
dòng tiêu đề của cửa sổ. Ví dụ, khi chọn contact số 1 thì tiêu đề cửa sổ sẽ biến thành
“Contact – Donald Trump”.
20
Để thực hiện yêu cầu này chúng ta có thể bind trực tiếp thuộc tính Text của Form với
một thuộc tính của view model ContactsViewModel. 
Điều chỉnh khai báo của lớp ContactsViewModel để lớp này thực thi interface
INotifyPropertyChanged.

1. public class ContactsViewModel : INotifyPropertyChanged


2. {

Việc này là bắt buộc để chúng ta có thể thông báo về sự thay đổi giá trị của object tới
điều khiển. Khi nhận được thông báo này thì điều khiển mới cập nhật giá trị của mình.

Bổ sung code sau vào cuối ContactsViewModel

1. public string Title


2. {
3. get {
4. if (ContactBindingSource.Current == null) return "Contacts";
5. return $"Contact - {(ContactBindingSource?.Current as Contact)?.ContactName}"
6. }
7. }
8. public void Initialize()
9. {
10. ContactBindingSource.CurrentChanged += delegate { Notify("Title"); };
11. }
12.
13. public event PropertyChangedEventHandler PropertyChanged;
14. private void Notify([CallerMemberName] string property = "")
15. {
16. PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(property));
17. }

Điều chỉnh code behind của Contacts

1. using System.Windows.Forms;
2.
3. namespace App
4. {
5. public partial class Contacts : Form
6. {
7. private ViewModels.ContactsViewModel _vm = new ViewModels.ContactsViewModel()
8.
9. public Contacts()
10. {
11. InitializeComponent();
12.
13. _vm.ContactBindingSource = contactBindingSource;
14. _vm.EmailBindingSource = emailsBindingSource;
15. _vm.PhoneBindingSource = phonesBindingSource;
16.
17. _vm.Initialize();
18.
19. Load += delegate { _vm.Load(); };
20.
21. buttonNew.Click += delegate { _vm.New(); };
22. buttonDelete.Click += delegate { _vm.Delete(); };
23. buttonSave.Click += delegate { _vm.Save(); };
24. buttonFirst.Click += delegate { _vm.First(); };
25. buttonLast.Click += delegate { _vm.Last(); };
26. buttonPrevious.Click += delegate { _vm.Previous(); };
27. buttonNext.Click += delegate { _vm.Next(); };
28.
29. buttonNewEmail.Click += delegate { _vm.NewEmail(); };
30. buttonDeleteEmail.Click += delegate { _vm.DeleteEmail(); };
31. buttonNewPhone.Click += delegate { _vm.NewPhone(); };
32. buttonDeletePhone.Click += delegate { _vm.DeletePhone(); };
33.
34. DataBindings.Add("Text", _vm, "Title");
35. }
36. }
37. }
20
Dịch và chạy thử chương trình

Bind windows title with property

Một số nhận xét


Tôi tin rằng bạn có thể thực hiện phần thực hành bên trên một cách dễ dàng. Bạn chắc
cũng thấy nó không hề khó khăn và rất ít code. Thậm chí, nếu so với cách trước đây bạn
thường làm, nó còn đơn giản hơn là đằng khác.

Thực ra, qua bài thực hành vừa rồi bạn đã thực hiện hầu hết các yêu cầu của mô hình UI
tự tạo.

Thật vậy.

Bạn đã phân tách code ra thành phần ViewModel (lớp ContactsViewModel), thành phần
View (form Contacts). Bản thân Model (lớp Contact, Phone, Email) bạn đã tạo ra từ bài
trước rồi.

ContactsViewModel chịu trách nhiệm cho xử lý dữ liệu và xử lý sự kiện. Form Contacts


chỉ đảm nhiệm hiển thị dữ liệu và nhận input từ người dùng.

Bạn có lẽ thấy, việc xây dựng một ứng dụng LOB giờ không còn quá lằng nhằng về code
nữa. Trong code behind của form giờ chỉ còn thực hiện binding (dữ liệu) hoặc delegate
(sự kiện) về ViewModel.

Cũng nên để ý rằng, nhờ cơ chế Databinding, sự thay đổi dữ liệu trên giao diện sẽ được
phản hồi ngay về kho dữ liệu đang nằm ở ViewModel. Và sự thay đổi dữ liệu ở ViewModel
sẽ được tự động cập nhật trên View. Bạn không cần cập nhật bằng tay. Quá tốt phải
không ạ!

Bạn hãy so sánh thử với cách trước đây bạn thiết kế giao diện và lập trình winform xem
có khác nhau không? Và bạn có thể tiết kiệm bao nhiêu thời gian khi làm theo cách mới
này? Chưa kể đến việc bạn sẽ ít mắc lỗi hơn (viết code ít hơn mà!), và chương trình sẽ
ổn định hơn.

Bạn cũng đã thấy, giờ đây quy trình xây dựng chương trình đã rất rõ ràng: (1) Xây dựng
các lớp Model, tức là các lớp thể hiện các thực thể cần quản lý; (2) Xây dựng các lớp
Vi M d l để ử lý dữ liệ l i ự kiệ (3) Thiết kế i diệ (4) Ghé ối i diệ
ViewModel để xử lý dữ liệu, logic, sự kiện; (3) Thiết kế giao diện; (4) Ghép nối giao diện
20
với ViewModel tương ứng.

Vấn đề cốt lõi là bạn phải phân tích bài toán cần giải quyết một cách chi tiết.

Kết phần
Bài viết này đã đưa ra một mô hình UI tự tạo đơn giản làm cơ sở cho việc xây dựng ứng
dụng trên winform. Từ mô hình này, bạn đã biết cần phân chia code ra các thành phần,
cũng như trình tự xây dựng các phần. Bạn cũng đã học được kỹ thuật thiết kế giao diện
của winform một cách nhanh chóng và dễ dàng.

Tuy nhiên, nếu so với phân tích ở phần 1 của loạt bài này thì còn một số vấn đề nữa
chúng ta vẫn chưa giải quyết xong. Mời bạn tiếp tục theo dõi phần 3 của loạt bài này.

Tải mã nguồn Giải pháp winforms (2): áp dụng T ẢI MÃ NG U ỒN


mô hình kiến trúc UI
 1 file(s)  5,63Mb

+ Nếu bạn thấy site hữu ích, trước khi rời đi hãy giúp đỡ site bằng một hành động nhỏ để
site có thể phát triển và phục vụ bạn tốt hơn.

+ Nếu bạn thấy bài viết hữu ích, hãy giúp chia sẻ tới mọi người.

+ Nếu có thắc mắc hoặc cần trao đổi thêm, mời bạn viết trong phần thảo luận cuối trang.

Cảm ơn bạn!

Loạt bài “Các giải pháp dành cho lập trình winform”:

Phần 1 – Lỗi thường gặp trong lập trình winforms

Phần 2 – Thiết kế giao diện với Data Sources và BindingSource

Phần 3 – Phân chia code thành module sử dụng Interface

Phần 4 – Sử dụng thư viện DevExpress cho winforms

Phần 5 – Sử dụng Data Binding

Phần 6 – Sử dụng Entity Framework

You might also like