Download as docx, pdf, or txt
Download as docx, pdf, or txt
You are on page 1of 155

BM/QT10/P.

ĐTSV/04/04
Ban hành lần: 3

UBND TỈNH BÀ RỊA – VŨNG TÀU


TRƯỜNG CAO ĐẲNG KỸ THUẬT CÔNG NGHỆ

GIÁO TRÌNH
MÔ ĐUN: LẬP TRÌNH ỨNG DỤNG WPF
NGHỀ: CÔNG NGHỆ THÔNG TIN
TRÌNH ĐỘ: CAO ĐẲNG

(Ban hành kèm theo Quyết định số: /QĐ-CĐKTCN


ngày…….tháng….năm ................... của Hiệu trưởng Trường Cao đẳng Kỹ thuật
Công nghệ BR – VT)
BÀ RỊA-VŨNG TÀU, NĂM 2020.
TUYÊN BỐ BẢN QUYỀN
Nhằm đáp ứng nhu cầu học tập và nghiên cứu cho giảng viên và sinh viên
nghề Công nghệ Thông tin trong trường Cao đẳng Kỹ thuật Công nghệ Bà Rịa –
Vũng Tàu, chúng tôi đã thực hiện biên soạn tài liệu Lập trình ứng dụng WPF
này.
Tài liệu được biên soạn thuộc loại giáo trình phục vụ giảng dạy và học tập,
lưu hành nội bộ trong Nhà trường nên các nguồn thông tin có thể được phép
dùng nguyên bản hoặc trích dùng cho các mục đích về đào tạo và tham khảo.
Mọi mục đích khác mang tính lệch lạc hoặc sử dụng với mục đích kinh
doanh thiếu lành mạnh sẽ bị nghiêm cấm.
LỜI GIỚI THIỆU

Giáo trình Lập trình ứng dụng WPF được biên soạn dựa trên khung
chương trình đào tạo Cao đẳng nghề Công nghệ Thông tin đã được Trường Cao
đẳng Kỹ thuật Công nghê Bà Rịa – Vũng Tàu phê duyệt.

Bên cạnh đó nhằm giúp cho người học các kiến thức và kỹ năng cần thiết
để thiết kế và lập trình được các ứng dụng nhỏ trong cuộc sống hằng ngày .

Tác giả đã nghiên cứu một số tài liệu, trang web liên quan kết hợp với kinh
nghiệm làm việc, giảng dạy thực tế để biên soạn giáo trình này.

Trong giáo trình này bao gồm các bài sau:

Bài 1: Tổng quan về WPF

Bài 2: Bố trí giao diện

Bài 3: Sử dụng các điều khiển cơ bản

Bài 4: Tạo hộp chọn font chữ

Bài 5: Tạo hộp chọn hình ảnh

Bài 6: Sử dụng Expander

Bài 7: Tạo hộp soạn thảo văn bản

Bài 8: Tạo menu

Bài 9: Tạo ToolBar

Bài 10: Tạo ContextMenu

Bài 11: Tạo StatusBar

Bài 12: Sử dụng Style

Bài 13: Sử dụng Template

Bài 14: Truy xuất cơ sở dữ liệu

Với tiêu chí trình bày cô động, dễ hiểu áp dụng thực tế, kèm theo chi tiết
các bước hướng dẫn thực hành cụ thể giúp cho người học dễ tiếp thu các kiến
thức cần thiết và hình thành được kỹ năng thực hành và rèn luyện thao tác.
1
Trong quá trình biên soạn, chắc chắn giáo trình còn nhiều thiếu sót. Tác giả
rất mong nhận được ý kiến đóng góp của quý thầy/cô và các em sinh viên để
tiếp tục hoàn thiện hơn.

Xin chân thành cảm ơn quý đồng nghiệp, bạn bè đã có những ý kiến đóng
góp trong quá trình xây dựng giáo trình này.

Bà Rịa – Vũng Tàu, ngày …… tháng …… năm 2020

Tham gia biên soạn

1. Trần Thị Thanh Hương – Chủ biên

2
MỤC LỤC
LỜI GIỚI THIỆU..................................................................................................1
BÀI 1: GIỚI THIỆU TỔNG QUAN.....................................................................8
1.1. Khái niệm WPF..............................................................................................8
1.2. Các thành phần của WPF.............................................................................10
1.3. Tạo ứng dụng WPF đầu tiên.........................................................................18
Câu hỏi ôn tập và bài tập.....................................................................................21
BÀI 2: BỐ TRÍ GIAO DIỆN..............................................................................22
2.1. Giới thiệu chung...........................................................................................22
2.2. Sử dụng các Panel thông dụng.....................................................................24
Câu hỏi ôn tập và bài tập.....................................................................................30
BÀI 3: SỬ DỤNG CÁC ĐIỀU KHIỂN CƠ BẢN..............................................32
3.1. Quy trình tạo điều khiển...............................................................................32
3.2. Tạo các điều khiển cơ bản............................................................................35
Câu hỏi ôn tập và bài tập.....................................................................................49
BÀI 4: TẠO HỘP THOẠI FONT CHỮ.............................................................50
4.1. Tạo điều khiển ComboBox, ListBox............................................................50
4.2. Đọc danh sách font chữ................................................................................51
4.3. Nạp dữ liệu vào ComboBox, ListBox..........................................................51
Câu hỏi ôn tập và bài tập.....................................................................................54
BÀI 5: TẠO HỘP CHỌN HÌNH ẢNH...............................................................56
5.1. Thêm dữ liệu vào Resource..........................................................................56
5.2. Khai báo dữ liệu từ resource cho Control....................................................58
Câu hỏi ôn tập và bài tập.....................................................................................59
BÀI 6: SỬ DỤNG EXPANDER.........................................................................60
6.1. Tạo Expander...............................................................................................60
6.2. Đặt ListBox bên trong Expander..................................................................61
6.3. Khai báo các chỉ mục con.............................................................................62

3
6.4. Trang trí các chỉ mục con.............................................................................63
Câu hỏi ôn tập và bài tập.....................................................................................64
BÀI 7: TẠO HỘP SOẠN THẢO VĂN BẢN RICHTEXTBOX.......................65
7.1. Tạo Control...................................................................................................65
7.2. Tạo chức năng cơ bản...................................................................................66
7.3. Giao diện Command.....................................................................................66
Câu hỏi ôn tập và bài tập.....................................................................................68
BÀI 8: TẠO MENU............................................................................................70
8.1. Xây dựng menu và các mục đơn giản..........................................................70
8.2. Tạo các Menu có trạng thái Checked/Unchecked........................................76
8.3. Tạo mục Menu có biểu tượng hình ảnh........................................................77
Câu hỏi ôn tập và bài tập.....................................................................................79
BÀI 9 : TẠO TOOLBAR....................................................................................80
9.1. Tạo nút công cụ đơn giản.............................................................................80
9.2. Tạo nút công cụ trạng thái............................................................................84
Câu hỏi ôn tập và bài tập.....................................................................................85
BÀI 10: TẠO CONTEXTMENU.......................................................................87
10.1. Context Menu riêng biệt.............................................................................87
10.2. Context Menu chia sẽ (Shared Context Menu)..........................................90
Câu hỏi ôn tập và bài tập.....................................................................................92
BÀI 11: TẠO STATUSBAR..............................................................................95
11.1. Phần tử văn bản..........................................................................................95
11.2. Phần tử Progress Bar..................................................................................98
11.3. Phần tử hình ảnh.........................................................................................99
11.4. Mã lệnh tổng hợp......................................................................................100
Câu hỏi ôn tập và bài tập...................................................................................101
BÀI 12: XỬ LÝ SỰ KIỆN VÀ DÙNG LỆNH.................................................103
12.1. Xử lý sự kiện............................................................................................103

4
12.2. Lệnh..........................................................................................................114
Câu hỏi ôn tập và bài tập...................................................................................121
BÀI 13: SỬ DỤNG STYLE..............................................................................123
13.1. Các thành phần thuộc tính trong Style.....................................................123
13.2. Tạo tập tin Style Resource Dictionary.....................................................128
13.3. Sử dụng tập tin Style Resource Dictionary..............................................129
Câu hỏi ôn tập và bài tập...................................................................................130
BÀI 14: SỬ DỤNG TEMPLATE.....................................................................131
14.1. Control Template......................................................................................131
14.2. Data Template..........................................................................................135
Câu hỏi ôn tập và bài tập...................................................................................136
BÀI 15: TRUY XUẤT CƠ SỞ DỮ LIỆU........................................................138
15.1. Tạo ADO.NET Entyty Data Model..........................................................138
15.2. Giới thiệu các lớp đối tượng.....................................................................144
15.3. Hiển thị dữ liệu trên ListBox/ComboBox................................................145
15.4. Hiển thị dữ liệu trên DataGrid..................................................................146
15.5. Thêm, xóa, cập nhật dữ liệu.....................................................................146
Câu hỏi ôn tập và bài tập...................................................................................147
TÀI LIỆU THAM KHẢO.................................................................................150

5
GIÁO TRÌNH MÔ ĐUN
Tên mô đun: Lập trình ứng dụng WPF
Mã mô đun: MĐ 24
Vị trí, tính chất, ý nghĩa và vai trò của mô đun:
- Vị trí của mô đun: được bố trí sau khi học xong các môn cơ sở và Lập trình
Windows.
- Tính chất của mô đun: là mô đun nghề tự chọn của trình độ Cao đẳng nghề
Công nghệ Thông tin, cung cấp kiến thức và kỹ năng tạo ứng dụng WPF với
giao diện chuyên nghiệp.
- Ý nghĩa và vai trò của môn học/mô đun: Môn học giúp làm quen với ứng dụng
WPF, thực hành được các giao diện lập trình ứng dụng nhỏ như: quản lý quán
café, quản lý khách sạn, quản lý nhân viên, quản lý sinh viên….
Mục tiêu của mô đun:
- Về kiến thức:
+ Biết ưu điểm của XAML, WPF trong phát triển ứng dụng Windows
+ Biết quy trình tạo project WPF
+ Biết công dụng của các loại panel, control trong WPF
+ Trình bày công dụng của Menu, Toolbar, ContextMenu, StatusBar
+ Trình bày công dụng và quy trình sử dụng Style, Template
+ Biết quy truy xuất CSDL trong WPF
- Về kỹ năng:
+ Tạo project WPF
+ Sử dụng hợp lý các loại panel, control trong thiết kế giao diện cho
ứng dụng WPF
+ Tạo Menu, Toolbar, ContextMenu, StatusBar cho ứng dụng
+ Sử dụng Style và Control Template cho giao diện
+ Sử dụng Data Template hiển thị dữ liệu
+ Truy xuất CSDL trong WPF
- Về năng lực tự chủ và trách nhiệm:
+ Lưu solution, project đúng đường dẫn

6
+ Tự phát triển ứng dụng với giao diện chuyên nghiệp
+ Tham gia phát triển ứng dụng quản lý cho các tổ chức, doanh nghiệp,
công ty phần mềm
+ Rèn luyện và nâng cao kỹ năng lập trình theo công nghệ hiện đại
+ Vận dụng ngôn ngữ XAML trong việc tự học thiết kế giao diện cho các
ứng dụng di động
+ Thực hiện các bài thực hành đảm bảo đúng trình tự, an toàn.
Nội dung của mô đun:

7
BÀI 1: GIỚI THIỆU TỔNG QUAN
Mã bài: 24.01
Giới thiệu:
Windows Presentation Foundation hay gọi tắt là WPF – là một nền tảng
cho phép developer có thể tạo ra các ứng dụng trên nền .NET framework cho
Windows nói chung. Cũng có thể gọi WPF là một GUI framework. Nó ra đời
sau Winform và tốt hơn người tiền nhiệm về mọi mặt..
Mục tiêu:
- Trình bày được khái và mục tiêu cơ bản của WPF
- Trình bày được khái niệm và vai trò của XAML trong việc tạo môi
trường làm việc chung giữa người thiết kế giao diện và người lập trình
- Tạo được ứng dụng WPF đơn giản
- Đảm bảo quy tắc thẻ mở, đóng
- Lưu project, Solution đúng đường dẫn
Nội dung chính:

1.1. Khái niệm WPF


WPF, viết tắt của Windows Presentation Foundation, là hệ thống API mới hỗ trợ
việc xây dựng giao diện đồ hoạ trên nền Windows. Được xem như thế hệ kế tiếp
của WinForms, WPF tăng cường khả năng lập trình giao diện của lập trình viên
bằng cách cung cấp các API cho phép tận dụng những lợi thế về đa phương tiện
hiện đại. Là một bộ phận của .NET Framework 3.0, WPF sẵn có trong Windows
Vista và Windows Server 2008. Đồng thời, WPF cũng có thể hoạt động trên nền
Windows XP Service Pack 2 hoặc mới hơn, và cả Windows Server 2003.
WPF được xây dựng nhằm vào ba mục tiêu cơ bản:
 Cung cấp một nền tảng thống nhất để xây dựng giao diện người dùng;
 Cho phép người lập trình và người thiết kế giao diện làm việc cùng nhau một
cách dễ dàng;
 Cung cấp một công nghệ chung để xây dựng giao diện người dùng trên cả
Windows và trình duyệt Web.

8
 Trước khi WPF ra đời, việc tạo giao diện người dùng theo những yêu cầu
mô tả ở ví dụ trên đòi hỏi sử dụng rất nhiều công nghệ khác nhau (xem
Bảng 2.1). Để tạo form, các control và các tính năng kinh điển khác của
một giao diện đồ họa Windows, thông thường lập trình viên sẽ chọn
Windows Forms, một phần của .NET Framework. Nếu cần hiển thị văn
bản, Windows Forms có một số tính năng hỗ trợ văn bản trực tiếp hoặc
có thể sử dụng Adobe’s PDF để hiển thị văn bản có khuôn dạng cố định.
Đối với hình ảnh và đồ họa 2 chiều, lập trình viên sẽ dùng GDI+, một mô
hình lập trình riêng biệt có thể truy nhập qua Windows Forms. Để hiển
thị video hay phát âm thanh, lập trình viên lại phải sử dụng Windows
Media Player, và với đồ họa 3 chiều, anh ta lại phải dùng Direct3D, một
thành phần chuẩn khác của Windows. Tóm lại, quá trình phát triển giao
diện người dùng theo yêu cầu trở nên phức tạp, đòi hỏi lập trình viên quá
nhiều kỹ năng công nghệ.
Windows Windows
WPF
Forms/
Forms
GDI+
Giao diện đồ
họa (form và các X X
control)
On-screen văn X X
bản
Fixed-format X
văn bản
Hình ảnh X X
Video và âm X
thanh
Đồ họa 2 chiều X X
Đồ họa 3 chiều X
Bảng 1.1. Thành phần giao diện theo yêu cầu và những công nghệ chuyên
biệt cần thiết để tạo chúng.

9
1.2. Các thành phần của WPF
Giống như các thành phần khác của .NET Framework, WPF tổ chức các
chức năng theo một nhóm namespace cùng trực thuộc namespace
System.Windows. Bất kể chức năng nào được sử dụng, cấu trúc cơ bản của
mọi ứng dụng WPF đều gần như nhau. Là ứng dụng Windows độc lập hay là
một XBAP, một ứng dụng WPF điển hình bao giờ cũng gồm một tập các trang
XAML và phần code tương ứng được viết bằng C# hoặc Visual Basic, còn gọi
là các file code-behind. Tất cả các ứng dụng đều kế thừa từ lớp chuẩn
Application của WPF. Lớp này cung cấp những dịch vụ chung cho mọi ứng
dụng, chẳng hạn như các biến lưu trữ trạng thái của ứng dụng, các phương thức
chuẩn để kích hoạt hay kết thúc ứng dụng.
Mặc dù WPF cung cấp một nền tảng thống nhất để tạo giao diện người
dùng, những công nghệ mà WPF chứa đựng có thể phân chia thành những
thành phần độc lập. Nhân của WPF là cơ chế tạo sinh đồ họa dựa trên vector và
độc lập với độ phân giải nhằm tận dụng những lợi thế của phần cứng đồ họa
hiện đại. WPF được mở rộng với các tập tính năng phát triển ứng dụng bao gồm
XAML, các control, cơ chế móc nối dữ liệu, layout, đồ họa 2 chiều, ba chiều,
hoạt họa, style, khuôn dạng mẫu, văn bản, media, text và in ấn. WPF nằm
trong .NET Framework, nên ngoài ra, ứng dụng WPF có thể kết hợp các thành
Mặc dù WPF cung cấp một nền tảng thống nhất để tạo giao diện người
dùng, những công nghệ mà WPF chứa đựng có thể phân chia thành những
thành phần độc lập. Nhân của WPF là cơ chế tạo sinh đồ họa dựa trên vector và
độc lập với độ phân giải nhằm tận dụng những lợi thế của phần cứng đồ họa
hiện đại. WPF được mở rộng với các tập tính năng phát triển ứng dụng bao gồm
XAML, các control, cơ chế móc nối dữ liệu, layout, đồ họa 2 chiều, ba chiều,
hoạt họa, style, khuôn dạng mẫu, văn bản, media, text và in ấn. WPF nằm
trong .NET Framework, nên ngoài ra, ứng dụng WPF có thể kết hợp các thành
phần khác có trong thư viện lớp của .NET Framework.

10
Hình 1.1. Các thành phần cơ bản của WPF
3.1 Layout và Control
Để sắp đặt các thành phần khác nhau trên giao diện, ứng dụng WPF sử
dụng panel. Mỗi panel có thể chứa các thành phần con, bao gồm các control
như nút bấm hay hộp thoại, hay bản than những panel khác. Những loại panel
khác nhau cho phép sắp xếp thành phần con theo những cách khác nhau. Ví dụ,
DockPanel cho phép các thành phần con có thể được đặt dọc theo cạnh của
panel đó, trong khi Grid cho phép sắp đặt các thành phần con của nó trên một
lưới tọa độ.

Giống như bất kỳ một công nghệ giao diện người dùng nào, WPF cung
cấp một số lượng lớn các control. Ngoài ra, người dùng có thể tùy ý định nghĩa
các control theo ý mình. Các control chuẩn gồm Button, Label, TextBox,
ListBox, Menu, Slider, hay phức tạp hơn có SpellCheck, PasswordBox…
Các sự kiện do người dùng tạo ra, như di chuyển chuột hay ấn phím, có thể
được các control nắm bắt và xử lý. Trong khi các control và các thành phần
giao diện khác có thể được đặc tả đầy đủ bằng XAML, các sự kiện bắt buộc
phải được xử lý bằng mã trình.
3.2 Style và Template
Giống như sử dụng Cascading Style Sheets (CSS) đối với HTML, việc
định ra thuộc tính đồ họa cho các đối tượng giao diện một lần, rồi sau đó áp

11
dụng lại cho các đối tượng khác cùng loại thường rất tiện lợi. WPF cũng cung
cấp tính năng tương tự bằng việc sử dụng thành phần Style của XAML. Ví dụ,
kiểu ButtonStyle có thể được định nghĩa như sau:

Bất kỳ nút bấm nào sử dụng kiểu này sẽ có nền màu đỏ và sử dụng font
chữ kích thước 16. Ví dụ:

Một Style có thể được dẫn xuất từ một Style khác, thừa kế hoặc chồng
lên những thuộc tính đã thiết lập. Mỗi style có thể định nghĩa các trigger cho
phép tạo ra những hiệu ứng tương tác đặc biệt, chẳng hạn như khi lướt chuột
qua nút bấm, nút bấm chuyển thành màu vàng.
WPF cũng hỗ trợ sử dụng template. Mỗi template tương tự như một style, và ở
hai dạng:

- Template cho dữ liệu: sử dụng thành phần DataTemplate của XAML để thiết
lập một nhóm thuộc tính hiển thị của dữ liệu như màu sắc, phương thức căn lề...
- Template cho control: sử dụng thành phần ControlTemplate của XAML để
định ra diện mạo của một control.
3.3. Text
Giao diện người dùng ít nhiều đều hiển thị chữ hay text. Đối với phần lớn
mọi người, đọc text trên màn hình thường khó hơn đọc trên giấy in. Đó là do
chất lượng hiển thị text trên màn hình kém hơn so với khi in ra giấy. WPF tập
trung giải quyết vấn đề này, làm chất lượng text hiển thị trên màn hình tương
đương trên giấy in. Cụ thể, WPF hỗ trợ các font chữ OpenType chuẩn, cho
phép sử dụng các thư viện font đã có. WPF cũng hỗ trợ công nghệ font chữ mới
ClearType, cho phép hiển thị các ký tự mịn hơn đối với mắt người, đặc biệt là
trên màn hình tinh thể lỏng (LCD).

12
Để nâng cao hơn nữa chất lượng hiển thị text, WPF cho phép một số
công nghệ khác như chữ ghép, theo đó một nhóm ký tự được thay thế bằng một
ảnh đơn nhất, tạo tâm lý thoải mái hơn khi đọc đối với người dùng.
3.4. Văn bản
WPF hỗ trợ ba dạng văn bản: văn bản cố định (fixed), văn bản thích nghi
(flow/adaptive) và văn bản XPS (XML Paper Specification). Kèm theo đó,
WPF cũng cung cấp các dịch vụ để tạo, xem, quản lý, ghi chú, đóng gói và in
ấn văn bản.
Văn bản cố định trông không đổi bất kể chúng được hiển thị trên màn
hình hay in ra máy in. Trong WPF, những văn bản dạng này được định nghĩa
bằng phần tử FixedDocument trong XAML và được hiển thị bằng control
DocumentViewer.
Trong khi đó, văn bản thích nghi thường chỉ dùng để đọc trên màn hình,
và có khả năng tự động thay đổi các thuộc tính hiển thị ảnh và text cho phù hợp
với kích thước cửa số hay các yếu tố môi trường khác nhằm nâng cao chất
lượng đọc cho người dùng. Văn bản thích nghi được định nghĩa bằng phần tử
FlowDocument. Để hiển thị văn bản thích nghi, WPF sử dụng một số control
khác nhau, chẳng hạn như FlowDocumentPageViewer,
FlowDocumentScrollViewer, FlowDocumentReader…

Hình 1.2. Minh họa về văn bản thích nghi trong WPF.
Văn bản XPS xây dựng trên cơ sở văn bản bất động của WPF. XPS là
một định dạng mở theo đặc tả XML, có khả năng sử dụng trên nhiều nền tảng
khác nhau, được thiết kế nhằm tạo thuận lợi cho việc xây dựng, chia sẻ, in ấn

13
và lưu trữ văn bản. Cũng như văn bản cố định, văn bản XPS được hiển thị bằng
DocumentViewer.

Hình 1.3. Minh họa về văn bản XPS trong WPF.


3.5. Hình ảnh
Trong WPF, hình ảnh được hiển thị nhờ control Image, ví dụ:

Control Image có thể hiển thị hình ảnh lưu trữ dưới nhiều khuôn dạng
khác nhau, bao gồm JPEG, BMP, TIFF, GIF và PNG. Nó cũng có thể hiển thị
hình ảnh dạng Windows Media Photo mới được sử dụng trong Windows Vista.
Bất kể ở khuôn dạng nào, WPF sử dụng Windows Imaging Component (WIC)
để tạo ra hình ảnh. Cùng với các codec dùng cho các khuôn dạng ảnh kể trên,
WIC cũng cung cấp một nền tảng chung để bổ sung codec khác.
3.6. Video và âm thanh
Khi tốc độ của các bộ xử lý và truyền thông mạng ngày một nâng cao,
video trở thành một phần tương tác lớn của người dùng với phần mềm. Người
dùng cũng sử dụng nhiều thời gian để nghe nhạc và các dạng âm thanh khác
trên máy tính. Do đó, WPF cung cấp tính năng hỗ trợ cả hai dạng media này
thông qua phần tử MediaElement. Control này có thể chơi các định dạng video
WMV, MPEG và AVI, và nhiều định dạng âm thanh khác nhau. Việc lập trình
để chạy một đoạn video trở nên khá đơn giản, như trong ví dụ sau:

14
3.7. Đồ họa 2 chiều
Trong 20 năm gần đây, việc tạo ra đồ họa hai chiều trên Windows dựa
trên Graphics Device Interface (GDI) và phiên bản sau của nó GDI+. Các ứng
dụng Windows Forms phải sử dụng chức năng này thông qua một namespace
khác hoàn toàn, bởi bản thân Windows Forms không tích hợp đồ họa 2 chiều.
Đối với đồ họa 3 chiều thì càng tồi hơn, Windows Forms phải dựa trên công
nghệ hoàn toàn biệt lập là Direct3D. Với WPF, vấn đề trở nên đơn giản hơn
nhiều. Cả đồ họa 2 chiều và 3 chiều đều có thể được tạo ra trực tiếp trong
XAML hoặc trong code sử dụng thư viện WPF tương ứng.
Đối với đồ họa 2 chiều, WPF định ra nhóm control của các khuôn hình
(shapes) mà ứng dụng có thể sử dụng để tạo nên hình ảnh, gồm:

 Line: vẽ đường thẳng qua 2 điểm.


 Elllipse: vẽ ellipse.
 Rectangle: vẽ chữ nhật.
 Polygon: vẽ đa giác.
 Polyline: vẽ đa giác mở.
 Path: vẽ hình theo một đường bất kỳ.
Mỗi khuôn hình đều có các thuộc tính phong phú cho phép hiển thị
với nhiều tính chất khác nhau: màu nền, màu biên… Một đặc điểm quan
trọng trong WPF là: vì mọi thứ đều được xây dựng trên một nền chung,
việc kết hợp các đặc tính và đối tượng khác nhau, chẳng hạn, lồng một
ảnh vào một hình chữ nhật, trở nên đơn giản. Điểm thú vị nữa là các đối
tượng hình học này còn có thể thu nhận các sự kiện từ phía người dùng
như một control, chẳng hạn sự kiện nhắp chuột.
Ngoài ra, WPF cũng cung cấp một nhóm chức năng hình học khác,
gọi là geometries, để làm việc với đồ họa hai chiều, như LineGeometry,
RectangleGeometry, EllipseGeometry, và PathGeometry. Dạng hình

15
học này có nhiều thuộc tính và chức năng tương tự như các khuôn hình đã
nêu trên. Điểm khác biệt quan trọng nhất là các geometries không được
dùng để hiển thị, chúng được dùng chủ yếu để tính toán hình học, ví dụ
như để định ra các vùng miền, theo dõi vị trí bấm chuột...
Thêm vào đó, WPF cung cấp lớp Transform cho phép thực hiện
các biến đổi hình học như xoay, dịch chuyển, co giãn đối tượng đồ họa;
hoặc cho phép thực hiện các hiệu ứng hoạt họa theo thời gian thông qua
các lớp Animation và Timing.
3.8. Đồ họa 3 chiều
WPF hỗ trợ đồ họa 3 chiều bằng việc gói các lời gọi API của Direct3D,
và do vậy, việc sử dụng chúng trở nên thống nhất và đơn giản hơn đáng kể. Để
hiển thị đồ họa ba chiều, ứng dụng WPF sử dụng control Viewport3D. Để tạo
ra các cảnh ba chiều, lập trình viên mô tả một hay nhiều mô hình, sau đó, phân
định cách thức các mô hình này được chiếu sáng hay hiển thị. Như thường lệ,
điều này được thực hiện bằng XAML, bằng code hay trộn cả hai. Để mô tả mô
hình, WPF cung cấp lớp GeometryModel3D để tạo ra hình dạng của mô hình.
Khi mô hình đã được định hình, diện mạo bên ngoài của nó có thể được điều
khiển bằng việc phủ lên các vật liệu (material). Chẳng hạn, lớp
SpecularMaterial cho phép tạo bóng trên bề mặt mô hình.
Bất kể được làm từ vật liệu gì, một mô hình có thể được chiếu sáng theo
nhiều cách. Lớp DirectionalLight cho phép ánh sáng tới từ một hướng xác
định, trong khi lớp AmbientLight tạo ra ánh sáng đồng đều trên mọi vật trong
cảnh. Cuối cùng, để định ra cách nhìn cảnh, lập trình viên phải định ra một
camera. Ví dụ, PerspectiveCamera cho phép phân định khoảng cách từ vị trí
nhìn tới vật thể và kiểu nhìn phối cảnh (tuân theo luật gần xa).

16
Hình 1. 4. Thiết lập đối tượng đồ họa ba chiều với WPF
Xây dựng cảnh ba chiều trực tiếp bằng XAML hay mã trình đều không
đơn giản. Do đó, chỉ nên dùng ứng dụng WPF để hiển thị cảnh ba chiều, việc
xây dựng cảnh nên được thực hiện bằng những công cụ đồ họa chuyên biệt.
3.9. Kết nối dữ liệu
Phần lớn các ứng dụng được tạo ra đều cung cấp cho người dùng phương
tiện để xem và sửa đổi dữ liệu. Trong các ứng dụng WPF, việc lưu trữ và truy
xuất dữ liệu đã được thực hiện bởi các công nghệ như Microsoft SQL Server và
ADO.NET. Sau khi dữ liệu được truy xuất và tải vào các đối tượng quản lý dữ
liệu trên ứng dụng, phần việc khó khăn của ứng dụng WPF mới bắt đầu. Về cơ
bản, có hai công việc phải thực hiện:
- Sao chép dữ liệu từ các đối tượng quản lý dữ liệu vào các control trên
giao diện, qua đó, dữ liệu có thể được hiển thị hay sửa đổi.
- Đảm bảo rằng những thay đổi trên dữ liệu từ các control được cập nhật
trở lại các đối tượng quản lý dữ liệu
Để đơn giản hóa quá trình phát triển ứng dụng, WPF cung cấp một cơ
chế móc nối dữ liệu để thực hiện tự động những bước này. Phần nhân của cơ
chế móc nối dữ liệu là lớp Binding mà nhiệm vụ của nó là liên kết control trên
giao diện (đích) với đối tượng quản lý dữ liệu (nguồn). Mối quan hệ này được
minh họa trong hình dưới đây:

17
Hình 1.5. Quan hệ giữa đối tượng dữ liệu và đối tượng phụ thuộc
Việc hỗ trợ móc nối dữ liệu được xây dựng ngay từ nhân của WPF. Tất
cả các đối tượng đồ họa trong WPF đều kế thừa từ DependencyObject, chúng
là các đối tượng phụ thuộc. Chức năng mà lớp cơ sở này hỗ trợ cho phép thực
hiện hiệu ứng hoạt họa, tạo kiểu mẫu (styling) và móc nối dữ liệu. Các đối
tượng này đều mang một thuộc tính đặc biệt gọi là DependencyProperty,
thuộc tính phụ thuộc. Phần lớn các thuộc tính hay dùng như Text, Content,
Width, Height, vân vân đều là các thuộc tính phụ thuộc. Tất cả các thuộc tính
phụ thuộc đều có thể tạo hiệu ứng hoạt họa, tạo kiểu và kết nối dữ liệu.

Cơ chế móc nối dữ liệu trong WPF còn cung cấp thêm những tính năng
như xác thực tính hợp lệ, sắp xếp, lọc và phân nhóm dữ liệu. Thêm vào đó, tính
năng móc nối dữ liệu cũng hỗ trợ sử dụng khuôn mẫu dữ liệu (data template) để
tạo ra các đối tượng giao diện tùy biến có kết nối dữ liệu, khi các control chuẩn
không phù hợp. Móc nối dữ liệu và khuôn dạng dữ liệu có thể được coi là tính
năng mạnh nhất của WPF.

1.3. Tạo ứng dụng WPF đầu tiên

18
Chọn loại ứng
Chọn ngôn ngữ
dụng
lập trình
Đặt tên và nơi lưu

Màn hình
thiết kết
Quản lý
Project
Hộp điều
khiển

Cửa sổ thuộc
Màn hình tính
XAML

Viết code cho đoạn chương trình trên, khi nhấp chọn vào nút Button, label sẽ
hiển thị nội dung “Chào mừng các bạn đến với môn học Lập trình WPF”.

19
Kết quả chương trình

Quản lý Solution và Project

20
Project được chạy đầu tiên

File cài đặt Form chạy


đầu tiên

File App

Thay đổi tên Form để


chạy đầu tiên

Câu hỏi ôn tập và bài tập


1. WPF là giao diện lập trình như thế nào?
2. Màn hình XAML dùng để làm gì?
3. Tiến hành cài đặt Visual Studio trên máy tính.
4. Tạo các ứng dụng project bằng lưu trữ trên máy tính gồm bài tập với tên:
LTWPF1 thực hành ví dụ đã học trong bài.

21
BÀI 2: BỐ TRÍ GIAO DIỆN
Mã bài: 24.02
Giới thiệu:
Bài này giới thiệu cách thức bố trí giao diện trong ứng dụng WPF. Phần
đầu sẽ giới thiệu về các dạng panel, một sự đổi mới trong phương thức bố trí
giao diện của ứng dụng WPF so với MFC, VB Forms hay ngay cả Windows
Forms nhằm tăng tính linh hoạt. Sau đó, các dạng panel thông dụng cùng với
đặc tính của chúng sẽ được trình bày thông qua các ví dụ đơn giản.
Mục tiêu:
- Trình bày được công dụng của các dạng Panel
- Lựa chọn đúng loại Panel theo từng yêu cầu của giao diện
- Xây dựng được giao diện bằng các dạng Panel
- Xây dựng được giao diện bằng XAML
- Tạo một Window/Page đơn giản
- Đảm bảo an toàn cho người và thiết bị.
Nội dung chính:
2.1. Giới thiệu chung
Như đã giới thiệu trong bài mở đầu, WPF sử dụng các dạng panel khác
nhau để bố trí các phần tử trên giao diện người dùng. Điều này xuất phát từ ý
tưởng kết hợp công nghệ giao diện mạnh như Windows Forms, với các kỹ thuật
sắp đặt (layout) của trình duyệt nhằm nâng cao tính linh hoạt trong việc bố trí
các phần tử trên giao diện.

Các công nghệ xây dựng giao diện như VB6 form, Access forms… dựa
trên nguyên tắc bố trí theo vị trí tuyệt đối. Nghĩa là, người lập trình phải xác
định giá trị tọa độ góc trên bên trái của một control (so với với góc trên bên trái
của một form) khi muốn đặt nó lên form. Điều này cho phép lập trình viên điều
khiển vị trí của control khá dễ dàng, nhưng lại thường đòi hỏi một lượng lớn mã
trình khi cần thay đổi kích thước form. Đây là phương pháp tiếp cận theo hướng
áp đặt (imperative), trong đó máy tính được chỉ rõ phải làm những bước gì, khi
nào và theo trình tự nào. Với cách thức bố trí này, các điều khiển như Label hay

22
Panel không tự động kéo giãn để phù hợp với kích thước phần nội dung chứa
trong nó. Và như vậy, nếu phần nội dung của một Label lớn hơn vùng có thể
hiển thị của Label đó, thì nội dung này sẽ bị cắt đi hoặc bị che lấp.

Trong khi đó, các phần tử giao diện Web trên trình duyệt được sắp xếp theo
phương thức khai báo (declarative), trong đó, người lập trình chỉ đưa ra những
thứ cần làm, còn máy tính sẽ giải quyết vấn đề làm như thế nào. Với phương
thức này, giao diện trên trình duyệt không đòi hỏi mã trình để thay đổi kích
thước các vùng chứa (containner). HTML cho phép ta định ra một chuỗi các
vùng chứa, ví dụ như các phần tử <div>, <table>, <tr> và <td>, để bố trí các
phần tử UI khác trong đó một cách linh động bên phải hoặc bên trái một đối
tượng; hay cũng có thể sắp xếp chúng theo vị trí tuyệt đối trên trang Web. Các
phần tử như <div> quan tâm tới kích thước bên trong nội dung của nó và sẽ tự
động giãn ra để chứa đủ nội dung bên trong.

Tuy nhiên, cả hai cách tiếp cận nêu trên đều khó có thể đạt được cách bố
trí như ý, mặc dù cách bố trí trên trình duyệt có giảm lượng code xử lý. Hiện
nay, Windows Forms đưa thêm những khái niệm như Docking (cập bến) hay
Anchoring (buông neo), bổ sung một cách tiếp cận kiểu khai báo linh hoạt hơn
để phát triển các ứng dụng trên máy trạm. WPF tiếp bước xu hướng này với
việc bố trí giao diện dựa trên khái niệm về panel.

Phần lớn các phần tử UI trong ứng dụng WPF chỉ có thể chứa duy nhất
một phần tử con. Chẳng hạn, đoạn mã XAML sau sẽ mắc lỗi biên dịch sau:
“The 'Button' object already has a child and cannot add 'CheckBox'. 'Button'
can accept only one child." Nghĩa là, đối tượng nút bấm ‘Button’ đã chứa một
phần tử con (cụ thể là đối tượng ‘TextBlock’) và do đó, không thể thêm vào
một đối tượng ‘CheckBox’ hay ‘ComboBox’ nữa.
Đoạn mã chương trình sau sẽ không được thực hiện vì không có các
Panel để chưa đựng chúng. Có thể sử dụng nhiều Panel lồng nhau hoặc các
Panel cùng cấp để chứa các điều khiển

23
Đoạn chương trình XAML sau đây sẽ dược thực hiện bằng cách tạo các
TextBlock, CheckBox, Combo trong Panel

Kết quả chương trình

2.2. Sử dụng các Panel thông dụng

Thay đổi Form


được chạy đầu tiên
trong màn hình làm
việc của App.xaml

2.2.1. StackPanel

24
StackPanel bố trí các phần tử con nằm trong nó bằng cách sắp xếp chúng
theo thứ tự trước sau. Các phần tử sẽ xuất hiện theo thứ tự mà chúng được khai
báo trong file XAML theo chiều dọc (ngầm định) hoặc theo chiều ngang.
2.2.1.1 Sắp xếp theo chiều dọc
Đoạn mã XAML minh họa việc sắp xếp các phần tử UI trong một đối
tượng Window bằng StackPanel theo chiều dọc:

Kết quả chương trình:

Trong trường hợp sắp xếp theo chiều dọc, nếu tổng chiều cao của các
phần tử con lớn hơn chiều cao của form chứa, thì các phần tử nằm ngoài form
sẽ không được nhìn thấy.
2.2.1.1. Sắp xếp theo chiều ngang
Sau đây là đoạn mã XAML minh họa việc sử dụng StackPanel để sắp xếp
các phần tử UI cùng ví dụ ở trên theo chiều ngang. Điểm khác biệt duy nhất ở

25
đây là thiết lập thêm thuộc tính Orientation="Horizontal" của đối tượng
StackPanel được sử dụng.

Kết quả chương trình:

Trong trường hợp sắp xếp theo chiều ngang, nếu tổng chiều rộng của
các phần tử con lớn hơn chiều rộng của form chứa, thì các phần tử nằm ngoài
form sẽ không được nhìn thấy.
2.2.2. WrapPanel
WrapPanel cho phép sắp xếp các phần tử từ trái sang phải. Khi một
dòng phần tử đã điền đầy khoảng không gian cho phép theo chiều ngang,
WrapPanel sẽ cuốn phần tử tiếp theo xuống đầu dòng tiếp theo (tương tự như
việc cuốn text).

26
Dưới đây là một ví dụ đơn giản về việc sử dụng WrapPanel:

Do chiều dài tổng cộng của 3 control lớn hơn chiều dài của Window,
đồng thời, chiều dài của 2 control đầu (TextBlock và Button) nhỏ hơn chiều dài
Window, WrapPanel sẽ xếp TextBlock cuối cùng xuống hàng dưới. Kết quả là:

2.2.3. DockPanel
DockPanel cho phép các phần tử bám lên các cạnh của panel DockPanel
bao chứa chúng, tương tự như khái niệm Docking trong Windows Forms. Nếu
như có nhiều phần tử cùng bám về một cạnh, chúng sẽ tuân theo thứ tự mà
chúng được khai báo trong file XAML. Sau đây là đoạn mã XAML minh họa
việc sử dụng DockPanel:

27
Phần tử Border cuối cùng sẽ điền vào phần không gian còn lại vì thuộc
tính DockPanel.Dock không xác định. Kết quả là:

2.2.4. CanvasPanel
Panel dạng Canvas sử dụng phương thức sắp xếp các phần tử UI theo vị
trí tuyệt đối bằng cách đặt thuộc tính Top (đỉnh) và Left (bên trái) của chúng.
Thêm vào đó, thay vì đặt thuộc tính Top, Left, ta có thể đặt thuộc tính Bottom
(đáy), Right (bên phải). Nếu ta đặt đồng thời thuộc tính Left và Right, thuộc
tính Right sẽ bị bỏ qua. Phần tử UI sẽ không thay đổi kích thước để thỏa mãn 2
thuộc tính trên cùng một lúc. Tương tự thuộc tính Top sẽ được ưu tiên hơn
thuộc tính Bottom. Các phần tử được khai báo sớm hơn trong file XAML sẽ có
thể bị che khuất phía dưới các phần tử được khai báo muộn hơn nếu vị trí của
chúng xếp chồng lên nhau.
Sau đây là một ví dụ minh họa việc sử dụng Canvas để sắp xếp các phần
tử UI.

28
Vị trí của phần tử TextBlock đầu tiên và phần tử Border được đặt theo
thuộc tính Top, Left, trong khi đó, phần tử Button được sắp vị trí theo thuộc
tính Bottom, Right. Border sẽ nằm chồng lên TextBlock đầu tiên vì có sự xếp
chồng về vị trí của hai phần tử này. Thêm vào đó, TextBlock đầu được khai báo
trước Border trong đoạn mã XAML. Kết quả là:

2.2.5. Grid
Panel dạng Grid là dạng panel hết sức linh hoạt, và có thể sử dụng để đạt
được gần như tất cả khả năng mà các dạng panel khác có thể làm được, mặc dù
mức độ khó dễ không giống nhau. Grid cho phép ta phân định các dòng và cột
theo dạng một lưới kẻ ô, và sau đó sẽ sắp đặt các phần tử UI vào các ô tùy ý.
Grid sẽ tự động chia đều các dòng và cột (dựa trên kích thước của phần nội
dung). Tuy nhiên, ta có thể sử dụng dấu sao (*) để phân định kích thước theo tỉ
lệ hoặc phân định giá trị tuyệt đối về chiều cao hoặc chiều rộng cho hàng và
cột. Ta có thể nhận biết sự khác biệt của 2 dạng phân định kích thước nêu trên
bằng cách thay đổi kích thước của form chứa panel Grid. Thêm vào đó, thuộc

29
tính ShowGridLines được đặt bằng True cho phép hiển thị các đường kẻ ô. Sau
đây là một ví dụ minh họa về việc sử dụng Grid với hai dạng phân định:

Câu hỏi ôn tập và bài tập


1. Tạo một project dưới dạng Console thực hiện khai báo các loại biến sau:
Biến chieudai, chieurong, chuvi, dientich kiểu dữ liệu int
Biến so1, so2, so3, min, max kiểu số thực (float)

30
2. Tạo một project dưới dạng Console thực hiện khai báo các loại hằng sau:
Hằng số thực p = 3.14
Hằng số nguyên n = 100 phần tử mảng

31
BÀI 3: SỬ DỤNG CÁC ĐIỀU KHIỂN CƠ BẢN
Mã bài: 24.03
Giới thiệu:
Trong lập trình giao diện người dùng, điều kiển (Control) là các nhân tố
quan trọng cấu thành nên giao diện người dùng, cho phép họ giao tiếp với ứng
dụng. Control có thể được hiểu một cách đơn giản là các phần tử trên một cửa
sổ như các nhãn (Label), hộp soạn thảo (TextBox), nút bẩm (Button), hộp danh
sách (ListBox, ComboBox),.. để hiển thị các thông tin tới người dùng và cho
phép người dùng nhập thông tin cần thiết cho chương trình. Phần này giới thiệu
cách tạo lập và sử dụng các Control cơ bản nhất của cửa sổ xây dựng bằng công
nghệ WPF.
Mục tiêu:
- Trình bày được khái niệm về control
- Trình bày các Control cơ bản trong WPF
- Dùng các Control để xây dựng giao diện trong WPF
- Đảm bảo an toàn cho người và thiết bị
Nội dung chính:
3.1. Quy trình tạo điều khiển
Điểm khác biệt cơ bản giữa mã lệnh tạo giao diện dựa trên WPF so với
phương pháp cũ là ứng dụng WPF sử dụng các đặc tả XAML (ngoài việc sử
dụng mã lệnh C# hay VB.Net) để định nghĩa giao diện, trong khi phương pháp
cũ phải sử dụng trực tiếp mã lệnh của C# hay VB.Net để định nghĩa giao diện.
Ví dụ, để xây dựng giao diện cửa sổ đơn giản như Hình 3.1 dưới đây.

Hình 3.1. Ví dụ cơ bản về các điều khiển

32
Có thể tạo giao diện bằng đoạn mã XAML

So sánh với code bằng Lập trình Windows Forms với ngôn ngữ C#
namespace Baitapcoban1
{
partial class frmdangnhap
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed;
otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.label1 = new System.Windows.Forms.Label();
this.label2 = new System.Windows.Forms.Label();
this.textBox1 = new System.Windows.Forms.TextBox();
this.textBox2 = new System.Windows.Forms.TextBox();
this.button1 = new System.Windows.Forms.Button();
this.button2 = new System.Windows.Forms.Button();
this.SuspendLayout();
//
// label1
//
this.label1.AutoSize = true;

33
this.label1.Location = new System.Drawing.Point(76, 70);
this.label1.Name = "label1";
this.label1.Size = new System.Drawing.Size(45, 13);
this.label1.TabIndex = 0;
this.label1.Text = "Họ đệm";
//
// label2
//
this.label2.AutoSize = true;
this.label2.Location = new System.Drawing.Point(76, 107);
this.label2.Name = "label2";
this.label2.Size = new System.Drawing.Size(29, 13);
this.label2.TabIndex = 1;
this.label2.Text = "Tên:";
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(164, 68);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(102, 20);
this.textBox1.TabIndex = 2;
//
// textBox2
//
this.textBox2.Location = new System.Drawing.Point(164, 104);
this.textBox2.Name = "textBox2";
this.textBox2.Size = new System.Drawing.Size(102, 20);
this.textBox2.TabIndex = 3;
//
// button1
//
this.button1.Location = new System.Drawing.Point(84, 160);
this.button1.Name = "button1";
this.button1.Size = new System.Drawing.Size(105, 32);
this.button1.TabIndex = 4;
this.button1.Text = "Xem thông tin";
this.button1.UseVisualStyleBackColor = true;
//
// button2
//
this.button2.Location = new System.Drawing.Point(228, 160);
this.button2.Name = "button2";
this.button2.Size = new System.Drawing.Size(62, 32);
this.button2.TabIndex = 5;
this.button2.Text = "Nhập lại";
this.button2.UseVisualStyleBackColor = true;
//
// frmdangnhap
//
this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size(800, 450);
this.Controls.Add(this.button2);
this.Controls.Add(this.button1);
this.Controls.Add(this.textBox2);
this.Controls.Add(this.textBox1);
this.Controls.Add(this.label2);
this.Controls.Add(this.label1);
this.Name = "frmdangnhap";
this.Text = "frmdangnhap";
this.ResumeLayout(false);
this.PerformLayout();

34
#endregion

private System.Windows.Forms.Label label1;


private System.Windows.Forms.Label label2;
private System.Windows.Forms.TextBox textBox1;
private System.Windows.Forms.TextBox textBox2;
private System.Windows.Forms.Button button1;
private System.Windows.Forms.Button button2;
}
}
Như vậy, điều chúng ta cần là tìm hiểu các thẻ XAML để mô tả các
Control cần thiết. Tuy nhiên không cần phải lo lắng nếu như chưa quen với các
mã lệnh XAML (dựa trên XML) này vì bộ công cụ từ Visual Studio.Net 2008
đã hỗ trợ thiết kế giao diện trực quan và tự động sinh mã XAML tương ứng.

3.2. Tạo các điều khiển cơ bản


3.2.1. Label (Nhãn)
Nhãn (Label) là các điều kiển để hiển thị các văn bãn tĩnh, thường được
sử dụng để làm nhãn cho các control khác như Textbox, ListBox, ComboBox,
….
Điều khiển Label trên của sổ Toolbox

Hình 3.2. Điều khiển Label

35
Hình 3.3. Ví dụ về Label
Label đuợc mô tả bằng đoạn mã XAML sau:

Nhãn được bắt đầu <Label> và kết thúc là </Label>, nội dung cũa nhãn
là đoạn văn bản đặt giữa cặp thẻ này. Trong ví dụ này “Họ đệm:” là nội dung
của nhãn.
Bên trong thẻ <Label> có rất nhiều đặc tính để mô tả về thẻ, trong đó:
- Height="30” : Độ cao của khung nhãn là 30px
- HorizontalAlignment="Left" : Nhãn được căn trái trong cửa sổ
- Margin="10,15,0,0" : có 4 giá trị là Left,Top,Right,Bottom
- Name="label1" : Tên của nhãn là lablel1
- VerticalAlignment="Top" :Nhãn được căn theo đỉnh của cửa sổ.
- Width="60": Chiều rộng của nhãn là 60px

36
Đặt tên Label
Thuộc tính Label
Sự kiện Label

Hình 3.4. Mô tả thuộc tính và sự kiện của Label


Bảng 3.1. Bảng mô tả các sự kiện của Label
Sự kiện Mô tả
Thực hiện công việc nào đó khi một phím được nhấn
KeyDown
xuống
KeyUp Thực hiện công việc nào đó khi một phím được nhả ra
Loaded Khi nhãn được hiển thị lên Form
LostFocus Khi con trỏ chuột thoát khỏi Label
MouseEnter Chuột nằm trong vùng thấy được của Label
MouseLeave Chuột ra khỏi vùng nhập liệu của Label
MouseMove Chuột được di chuyển trên Label
DataContextChanged Giá trị nội dung trong Label bị thay đổi
3.2.2. TextBox(Hộp soạn thảo)
Hộp soạn thảo (TextBox) là control cho phép người dùng nhập dữ liệu
dạng văn bản.
Điều khiển Textbox trên của sổ Toolbox

Hình 3.5. Điều khiển Textbox

37
Ví dụ về điều khiển Textbox trên Form

Hình 3.6. Ví dụ điều khiển Textbox


Dưới đây là đoạn mã XAML của hộp soạn thảo

Hộp soạn thảo được tạo nên bởi thẻ <TextBox/>. Nếu muốn thiết lập sẵn
nội dung mặc định cho hộp soạn thảo, ta đặt nội dung này vào giữa cặp thẻ
<TextBox/> Nội dung </TextBox>. Nếu không muốn đặt giá trị mặc định thì
không cần thẻ đóng </TextBox>.
Thẻ <TextBox/> cũng có nhiều đặc tính, trong đó:
- Margin="80,17,30,0": Cách lề trái 80, đỉnh cửa sổ 17, cạnh phải 30
- Name="textBox1": Tên của hộp soạn thảo là textBox1
- VerticalAlignment="Top": Căn theo đỉnh cửa sổ
Đặc điểm của hộp soạn thảo với các đặc tính trên là khi người dùng co dãn, thay
đổi kích thước cửa sổ, chiều rộng của hộp soạn thảo tự động co dãn theo.
Các sự kiện thường được sử dụng khi dùng điều khiển TextBox
Bảng 3.2. Bảng mô tả các sự kiện của Textbox
Sự kiện Mô tả
Thực hiện công việc nào đó khi một phím được nhấn
KeyDown
xuống

38
KeyUp Thực hiện công việc nào đó khi một phím được nhả ra
Loaded Khi Textbox được hiển thị lên Form
LostFocus Khi con trỏ chuột thoát khỏi Textbox
MouseDoubleClick Khi sự kiện nhấp đôi chuột trái
MouseDown Khi nhấp trái chuột
MouseEnter Chuột nằm trong vùng thấy được của Textbox
MouseLeave Chuột ra khỏi vùng nhập liệu của Textbox
MouseMove Chuột được di chuyển trên Textbox
TextChanged Giá trị nội dung trong Textbox bị thay đổi
3.2.3. Button( Nút bấm)
Nút bấm (Button) là loại điều khiển cho phép người dùng nhấn chuột để chọn
lệnh, khi nhấn vào nút bấm, nó sẽ sinh ra sự kiện Click và sẽ chạy các lệnh gắn
với sự kiện này.
Điều khiển Button trên hộp Toolbox

Hình 3.7. Điều khiển Button

Hình 3.8. Minh họa về điều khiển Button


Đoạn code phát sinh điều khiển Button trên XAML (chú ý lệnh mở và đóng thẻ)

39
Nút bấm được bắt đầu bằng thẻ <Button> và kết thúc bằng thẻ
</Button>. Nhãn của nút bấm được đặt trong cặp thẻ <Button> Nhãn nút bấm
</Button>.
Nút bấm có nhiều đặc tính, trong đó:
- Height="35": Chiều cao nút bấm là 35
- Width="110": Chiều rộng là 110
- HorizontalAlignment="Left": Căn theo lề trái
- VerticalAlignment="Bottom": Căn theo đáy cửa sổ
- Margin="16,0,0,27": Cách lề trái 16, cách đáy 27
- Name="button1": Tên nút bấm là button1
Bảng 3.3. Bảng mô tả các sự kiện của Button
Sự kiện Mô tả
Click Nhấp chuột vào điều khiển
Thực hiện công việc nào đó khi một phím được nhấn
KeyDown
xuống
KeyUp Thực hiện công việc nào đó khi một phím được nhả ra
Loaded Khi điều khiển được hiển thị lên Form
LostFocus Khi con trỏ chuột thoát khỏi Button
MouseDoubleClick Khi sự kiện nhấp đôi chuột trái
MouseEnter Chuột nằm trong vùng thấy được của Button
MouseLeave Chuột ra khỏi vùng nhập liệu của Button
MouseMove Chuột được di chuyển trên Button
Ví dụ về sự kiện Click với Button “Xem thông tin” ở trên Code được lập trình
trong file .cs như sau:

40
Kết quả chương trình khi nhấp vào nút “Xem thông tin”

Hình 3.9. Kết quả chương trình khi chạy Form

3.2.4. RadioButton

41
Radio Button: là hộp chọn theo nhóm, nghĩa là các hộp trong cùng một
nhóm sẽ loại trừ nhau, tại một thời điểm người dùng chỉ được chọn một trong
các mục. Vi dụ như hộp chọn giới tính, ta phải sử dụng radio vì tại một thời
điểm chỉ cho phép chọn Nam hoặc Nữ
Điều khiển RadioButton trên Toolbox

Hình 3.10. Điều khiển Button


Giao diện Button trên Form khi hiển thị

Radiobutton

Hình 3.11. Form hiển thị RadioButton

Đoạn mã XAML khi tạo Radiobutton

42
Radiobuttonđược tạo bởi thẻ <RadioButton> và kết thúc
bởi</RadioButton>, giữa cặp thẻ này là nhãn của RadioButton<RadioButton>
Nhãn </RadioButton>.
Thẻ này có đặc tính IsChecked="True" hoặc IsChecked="False". Mục
nào có thuộc tính này sẽ được tự động chọn khi cửa sổ bắt đầu hiển thị.
Đối với Radio Button, vì là hộp chọn loại trừ, nếu trong một cửa sổ có
nhiều nhóm Radio Button khác nhau thì các Radio Button của mỗi nhóm đuợc
phân biệt bởi đặc tính GroupName="TenNhom". Ví dụ, trên cùng một cửa sổ
có hai Radio Button chọn Giới tính (Nam; Nữ) và ba Radio Button khác chọn
nghề nghiệp (Kinh doanh; Kỹ Thuật; Marketing) thì các Radio Button Nam, Nu
phải có cùng GroupName với nhau, ba Radio Button Kinh doanh, Ky Thuat,
Marketting phải có cùng GroupName và khác với GroupName của nhóm giới
tính.
Đoạn mã lệnh minh họa kiểm tra mục chọn RadioButton

Kết quả chương trình

Hình 3.12. Kết quả hiển thị khi chọn RadioButton

43
Bảng 3.4. Bảng mô tả các sự kiện của RadioButton
Sự kiện Mô tả
Checked Khi RadioButton được đánh dấu chọn
Click Khi sự kiện chuột được sử dụng
Thực hiện công việc nào đó khi một phím được nhấn
KeyDown
xuống
KeyUp Thực hiện công việc nào đó khi một phím được nhả ra
Loaded Khi RadioButton được hiển thị lên Form
LostFocus Khi con trỏ chuột thoát khỏi RadioButton
MouseDoubleClick Khi sự kiện nhấp đôi chuột trái
MouseDown Khi nhấp trái chuột
MouseEnter Chuột nằm trong vùng thấy được của RadioButton
MouseLeave Chuột ra khỏi vùng nhập liệu của RadioButton
MouseMove Chuột được di chuyển trên RadioButton
UnChecked Khi RadioButton được bỏ dấu chọn

3.2.5. CheckBox
CheckBox: là hộp chọn mà người dùng có thể chọn một hoặc nhiều mục
cùng một lúc. Vi dụ như mục chọn Ngoại ngữ, cho phép người dùng chọn đồng
thời nhiều mục.

Hình 3.13. Hiển thị điều khiển CheckBox


Hiển thị CheckBox trên màn hình khi chạy chương trình

44
CheckBox

Hình 3.14. CheckBox khi chạy chương trình


Đoạn code hiển thị CheckBox bằng câu lệnh XAML

CheckBox được tạo bởi thẻ <CheckBox > và kết thúc bởi</CheckBox>,
giữa cặp thẻ này là nhãn của CheckBox <CheckBox> Nhãn </CheckBox>.
Thẻ có đặc tính IsChecked="True" hoặc IsChecked="False". Mục nào có
thuộc tính này sẽ được tự động chọn khi cửa sổ bắt đầu hiển thị.
Đoạn code sử dụng câu lệnh và điều khiển CheckBox

Kết quả chương trình:

45
Hình 3.15. Kết quả khi chạy chương trình

Bảng 3.5. Bảng mô tả các sự kiện của CheckBox


Sự kiện Mô tả
Checked Khi CheckBox được đánh dấu chọn
Click Khi sự kiện chuột được sử dụng
Thực hiện công việc nào đó khi một phím được nhấn
KeyDown
xuống
KeyUp Thực hiện công việc nào đó khi một phím được nhả ra
Loaded Khi CheckBox được hiển thị lên Form
LostFocus Khi con trỏ chuột thoát khỏi CheckBox
MouseDoubleClick Khi sự kiện nhấp đôi chuột trái
MouseDown Khi nhấp trái chuột
MouseEnter Chuột nằm trong vùng thấy được của CheckBox
MouseLeave Chuột ra khỏi vùng nhập liệu của CheckBox
MouseMove Chuột được di chuyển trên CheckBox
UnChecked Khi RadioButton được bỏ dấu chọn

3.2.6. ListBox

46
Hộp danh sách (ListBox) và là điều khiển hiển thị một danh sách các
mục theo từng dòng và cho phép người dùng chọn một hay nhiều phẩn tử của
danh sách.

Hình 3.16. Hiển thị của điều khiển ListBox


Ví dụ về hộp danh sách chọn Quê quán:

Hình 3.17. Hiển thị điều khiển ListBox trên Form


Đoạn mã lệnh XAML để tạo ListBox

ListBox được tạo bởi thẻ <ListBox> và kết thúc bằng thẻ đóng
</ListBox>

47
Mỗi phần tử của danh sách nằm trong cặp thẻ <ListBoxItem> Nhãn
</ListBoxItem> lồng bên trong cặp thẻ trên.

Đặc tính SelectedIndex="k" để yêu cầu tự động chọn phần thử thứ n
trong danh sách khi mở cửa sổ. Phần tử đầu tiên của danh sách có giá trị là 0,
phần tử cuối cùng là n-1. Nếu muốn khi mở cửa sổ không chọn phần tử nào thì
đặt giá trị k bằng -1.

Đoạn mã lệnh lấy mục chọn từ ListBox

Kết quả khi chạy chương trình


Bảng 3.6. Bảng mô tả các sự kiện của ListBox
Sự kiện Mô tả
Thực hiện công việc nào đó khi một phím được nhấn
KeyDown
xuống
KeyUp Thực hiện công việc nào đó khi một phím được nhả ra
Loaded Khi Textbox được hiển thị lên Form
LostFocus Khi con trỏ chuột thoát khỏi Textbox
MouseDoubleClick Khi sự kiện nhấp đôi chuột trái
MouseDown Khi nhấp trái chuột

48
MouseEnter Chuột nằm trong vùng thấy được của Textbox
MouseLeave Chuột ra khỏi vùng nhập liệu của Textbox
MouseMove Chuột được di chuyển trên Textbox
TextChanged Giá trị nội dung trong Label bị thay đổi

3.2.7. ComboBox

Bảng 3.2. Bảng mô tả các sự kiện của Textbox


Sự kiện Mô tả
Thực hiện công việc nào đó khi một phím được nhấn
KeyDown
xuống
KeyUp Thực hiện công việc nào đó khi một phím được nhả ra
Loaded Khi Textbox được hiển thị lên Form
LostFocus Khi con trỏ chuột thoát khỏi Textbox
MouseDoubleClick Khi sự kiện nhấp đôi chuột trái
MouseDown Khi nhấp trái chuột
MouseEnter Chuột nằm trong vùng thấy được của Textbox
MouseLeave Chuột ra khỏi vùng nhập liệu của Textbox
MouseMove Chuột được di chuyển trên Textbox
TextChanged Giá trị nội dung trong Label bị thay đổi

Câu hỏi ôn tập và bài tập


1. Viết chương trình cho phép người dùng nhập tên của mình và hiển thị câu:
Môn học Lập trình Windows Form chào bạn + <Tên vừa nhập>.
2. Viết chương trình nhập vào các thông tin:
 Tên
 Tuổi
 Địa chỉ
Xuất ra màn hình theo định dạng: Bạn tên <Tên>, <Tuổi> tuổi, ở <Địa
chỉ>

49
BÀI 4: TẠO HỘP THOẠI FONT CHỮ
Mã bài: 24.04
Giới thiệu:
Không dừng lại ở việc cung cấp những điều khiển UI như ComboBox,
ListBox, TextBox,…, với những chức năng cơ bản và đặc tính text đơn điệu
như trong Windows Form, WPF còn cho phép người lập trình tùy biến thuộc
tính của những điều khiển trên để biến chúng thành những điều khiển UI phức
hợp, với nhiều đặc tính giao diện phong phú, tinh tế, kết hợp text, hình ảnh,…
Để đạt được hiệu quả tương tự, với những công nghệ trước đây như MFC, cần
tiêu tốn nhiều công sức lập trình. Qua các ví dụ cụ thể trong bài giảng này,
chúng ta sẽ thấy WPF tạo ra chúng đơn giản như thế nào.
Mục tiêu:
- Biết công dụng của ComboBox, ListBox
- Chèn ComboBox, ListBox vào giao diện
- Nạp danh sách font chữ của hệ thống
- Hiển thị danh sách dữ liệu trong ComBoxBox, ListBox
- Thực hiện được các biện pháp an toàn cho máy tính
Nội dung chính:
4.1. Tạo điều khiển ComboBox, ListBox
Mục tiêu của phần này là tạo lập một điều khiển dạng ComboBox, trong
đó, liệt kê danh sách các phông chữ hệ thống. Tên của mỗi phông chữ lại được
hiển thị dưới dạng chính phông chữ đó. Điều này cho phép người dùng xem
trước định dạng phông chữ trước khi chọn chúng. Chúng ta đã quen thuộc với
dạng Combox này khi sử dụng các ứng dụng gần đây của Microsoft Office như
Word, Excel, PowerPoint,…
Khai báo để tạo ComboBox trong đoạn mã XAML:

50
Khai báo để tạo ListBox trong đoạn mã XAML:

4.2. Đọc danh sách font chữ


Đoạn mã code bằng XAML:

Trong phần khai báo tạo điều khiển ComboBox, ta khai báo nguồn dữ
liệu được dùng cho các mục trong hộp danh sách thông qua thuộc tính
ItemsSource. Bằng việc gán ItemsSource="{x:Static
Fonts.SystemFontFamilies}" ta định nghĩa nguồn dữ liệu này là danh
sách các phông chữ hiện có của hệ thống máy tính hiện thời. Thuộc tính
SelectedIndex cho phép định ra chỉ số của chỉ mục ngầm định được chọn
ban đầu trong danh sách phông, cụ thể trong trường hợp này là phông chữ đầu
tiên (SelectedIndex="0").

Trong phần khai báo định nghĩa thuộc tính dữ liệu của mỗi chỉ mục trong
ComboBox (phần tử <ComboBox.ItemTemplate>), ta lồng vào một điều
khiển TextBlock, trong đó, nội dung hiển thị là phông chữ tương ứng
(Text="{Binding}") và dạng phông hiển thị nội dung cũng chính là phông
chữ tương ứng với chỉ mục này (FontFamily="{Binding}").

4.3. Nạp dữ liệu vào ComboBox, ListBox


Đoạn mã code bằng XAML đầy đủ về chương trình Font chữ từ hệ thống:

51
Lựa chọn sự kiện điều khiển
ComboBox

Hình 4.1. Lựa chọn sự kiện cho điều khiển ComboBox

52
Đoạn Code bằng ngôn ngữ C# trong file .cs

Kết quả chương trình:

Hình 4.2. Lựa chọn Fon VNI-Vari


Kết quả chương trình:

53
Hình 4.3. Lựa chọn Font TimesNewRoman
Câu hỏi ôn tập và bài tập
1. Áp dụng câu lệnh switch …case để viết chương trình trên Console theo yêu
cầu sau: khai báo biến kiểu int luachon.

2. Áp dụng lệnh for hoặc lệnh foreach để thực hiện công việc sau:
- Tính tổng các số từ 1  n với n là số nguyên được nhập vào từ bàn
phím.

54
- Tính tổng các số chẵn và số lẽ từ 1  n với n là số nguyên được nhập
vào từ bàn phím.
- Chương trình mảng nhập, xuất, sắp xếp mảng 1 chiều với n là số nguyên

55
BÀI 5: TẠO HỘP CHỌN HÌNH ẢNH
Mã bài: 24.05
Giới thiệu:
Trong phần này, ta xây dựng một hộp danh mục (ListBox) các đồ uống
có kèm theo ảnh. Rõ ràng tính trực quan của giao diện người dùng sẽ tăng hơn
nhiều so với một danh sách dạng text đơn điệu.
Mục tiêu:
- Thêm các tập tin làm resource
- Hiển thị danh sách resource trong ComboBox, ListBox
- Cẩn thận truyền tham số có kiểu dữ liệu phù hợp cho hàm
- Đảm bảo an toàn cho người và thiết bị
Nội dung chính:
5.1. Thêm dữ liệu vào Resource
Trước hết, ta thêm các ảnh đồ uống cần thiết vào tài nguyên của project theo các
bước sau:
- Ở cửa sổ Solution Explorer, ta nhắp chuột phải vào tên project  Xuất
hiện bảng chọn chức năng.
- Chọn mục Add  Existing Item  Xuất hiện cửa sổ cho phép lựa
chọn file.

56
- Trong hộp danh sách Files of type, ta chọn Image Files  Các file ảnh
trong thư mục hiện thời sẽ xuất hiện.

- Tìm đến các file ảnh cần hiển thị trong danh sách và chọn OK.
- Kết quả, trong cửa sổ Solution Explorer, ta thấy xuất hiện các file
ảnh tương ứng.

57
5.2. Khai báo dữ liệu từ resource cho Control
Đoạn code chương trình bằng XAML để đưa hình ảnh dữ liệu vào

Như vậy, điểm mấu chốt để bổ sung thêm các thuộc tính giao diện như
ảnh, text, checkbox,…, vào mỗi chỉ mục của hộp danh sách chính là việc kết
hợp các phần tử UI riêng lẻ tương ứng vào cùng một phần tử Panel nằm trong
khai báo chỉ mục. Trong trường hợp này, với mỗi khai báo chỉ mục
<ListBoxItem> ta thêm vào một <StackPanel
Orientation="Horizontal">

theo chiều ngang, trong đó, chứa một phần tử <Image> và 1 phần tử
<TextBlock> . Nguồn dữ liệu ảnh được xác định qua thuộc tính
Source="<tên ảnh đã được bổ sung vào project>".

58
Kết quả chương trình:

Câu hỏi ôn tập và bài tập


Áp dụng lệnh while, do … while để thực hiện công việc sau:
- Tính tổng các số từ 1  n với n là số nguyên được nhập vào từ bàn
phím.
- Tính tổng các số chẵn và số lẽ từ 1  n với n là số nguyên được nhập
vào từ bàn phím.
- Chương trình mảng nhập, xuất, sắp xếp mảng 1 chiều với n là số nguyên

59
BÀI 6: SỬ DỤNG EXPANDER
Mã bài: 24.06
Giới thiệu:
Hộp mở rộng Expander là một trong những điều khiển UI mới được giới
thiệu trong WPF như một điều khiển cơ bản. Expander cho phép thu gọn hoặc
mở rộng một nội dung nào đó chứa trong nó, giống như một node trong
TreeView, bằng việc click vào biểu tượng mũi tên (hướng lên, nếu điều khiển
đang ở trạng thái mở rộng; hướng xuống, nếu đang ở trạng thái thu gọn). Điều
khiển này rất tiện lợi: Khi diện tích form chính quá chật hẹp vì nhiều chức năng
được trình bày trên cùng giao diện, ta có thể sử dụng Expander để chứa một số
chức năng ít dùng có thể tạm thời được ẩn dưới một tên nhóm chung.
Mục tiêu:
- Biết công dụng của Expander
- Thiết kế giao diện sử dụng Expander
- Đảm bảo an toàn cho người và thiết bị
Nội dung chính:
6.1. Tạo Expander

Hình 6.1. Hiển thị Expander Hình 6.2. Hiển thị danh sách Expander

60
Trong ví dụ sau đây, ta sẽ làm một menu chứa 2 mục là đồ uống và đồ ăn, mỗi
mục sẽ chứa danh sách các sản phẩm tương ứng mà nhà hàng cung cấp. Ta sử
dụng Expander để có thể mở rộng/thu gọn từng mục nêu trên.
Đoạn code XAML để thêm Expander

Hình 6.3. Kết quả sau khi thêm Expander

6.2. Đặt ListBox bên trong Expander


Đoạn code XAML để thêm ListBox

Hình 6.4. So sánh trước và sau khi có ListBox

61
6.3. Khai báo các chỉ mục con
Đoạn code XAML để thêm các mục con dành cho mục “Đồ uống”

Kết quả chương trình

Hình 6.5. Kết quả Expander đồ uống


Đoạn code XAML để thêm các mục con dành cho mục “Đồ ăn”

62
Kết quả chương trình

Hình 6.6. Kết quả Expander đồ ăn

6.4. Trang trí các chỉ mục con


Việc trang trí các chỉ mục con cần có cấu trúc thư mục để lưu trữ các hình ảnh
phù hợp với yêu cầu. Cấu trúc lưu trữ như sau:

63
Thư mục lưu trữ
hình ảnh

Hình 6.7. Thư mục lưu trữ hình ảnh

Lấy đường dẫn


hình để trang trí

Câu hỏi ôn tập và bài tập


1. Sử dụng câu lệnh break cho bài tập 5.1
2. Viết chương trình đặt một nhãn bất kỳ và thực hiện in ra câu lệnh “Chúc các
bạn học tốt môn học”.
3. Từ bài tập 2 cho phép người dùng nhập vào tên học sinh và nhảy tới vị trí câu
lệnh Chúc các bạn học tốt môn học”.

64
BÀI 7: TẠO HỘP SOẠN THẢO VĂN BẢN RICHTEXTBOX
Mã bài: 24.07
Giới thiệu:
Hộp soạn văn bản đa năng RichTextBox là một trong những điều khiển
có chức năng phong phú. Không chỉ cho phép soạn sửa và hiển thị các nội dung
text đơn thuần, RichTextBox còn cho phép thay đổi phông chữ (Verdana,
Times New Roman,…), kiểu chữ (nghiêng, đậm, gạch chân),… Đặc biệt, điều
khiển RichTextBox trong WPF/.NET 3.0 còn cho phép kiểm tra/gợi ý sửa đổi
lỗi chính tả tiếng Anh của nội dung văn bản chứa trong đó. RichTextBox trong
WPF/.NET 3.0 là phần tử được cải tiến về cơ bản so với phiên bản trước của
điều khiển RichTextBox trong .NET 2.0. Tuy nhiên, cùng với sự mở rộng về
chức năng là việc bổ sung các API mới cũng như những cách thức sử dụng
khác.
Mục tiêu:
- Biết công dụng của RichTextBox
- Thiết kế giao diện soạn thảo văn bản
- Tạo ứng dụng soạn thảo văn bản đơn giản
- Đảm bảo an toàn cho người và thiết bị.
Nội dung chính:
7.1. Tạo Control
Để thêm mới một hộp soạn thảo đa năng vào form, ta dùng mã XAML như sau:

65
Hình 7.1. Kết quả thêm RichTextBox vào Form

7.2. Tạo chức năng cơ bản


Thuộc tính x:Name là từ khoá xác định danh tính của RichTextBox được
tạo. Thuộc tính này đóng vai trò là tham chiếu cho phép ta sau này buộc mã
lệnh C# vào điều khiển. Thuộc tính MinHeight xác định số dòng có thể thấy
được của hộp soạn thảo, giá trị này ngầm định bằng 1.
Thuộc tính SpellCheck.IsEnabled="True" kích hoạt tính năng kiểm tra
lỗi chính tả tiếng Anh trong nội dung văn bản và gợi ý những từ đúng có thể để
thay thế, giống như Microsoft Word.
Tuy nhiên, nếu chỉ với một RichTextBox, ta không có cách nào để sửa
đổi định dạng của văn bản trong RichTextBox như đánh chữ nghiêng, chữ đậm,
đổi phông chữ, v.v…. Muốn đạt được điều này, ta phải buộc mã lệnh vào giao
diện Command của RichTextBox.

7.3. Giao diện Command


Microsoft chủ trương để người phát triển làm việc với RichTextBox
thông qua giao diện Command. Mặc dù khái niệm này không mới đối với phần
lớn người phát triển giao diện đồ hoạ người dùng, việc cài đặt và cú pháp trong
XAML có chút khác biệt.
Ta cần thêm một ToolBar và một số nút bấm hai trạng thái
(ToggleButton) để gắn lệnh điều khiển RichTextBox đã tạo. Thuộc tính
Command trên mỗi điểu khiển kể trên sẽ xác định chức năng mà ta muốn kích
hoạt trên RichTextBox,. Trong khi đó, thuộc tính CommandTarget xác định
RichTextBox nào ta muốn chức năng kích hoạt của các nút bấm nhằm vào. Sau
đây là đoạn mã XAML bổ sung thêm một ToolBar và 3 nút bấm hai trạng thái:

66
Mặ
c dù đoạn mã ví dụ chỉ bao gồm một số ít các nút lệnh
(Command="EditingCommands.ToggleBold",
Command="EditingCommands.ToggleBold",
Command="EditingCommands.ToggleItalic"), có tổng cộng 47
lệnh khác nhau mà ta có thể lựa chọn (có thể xem chúng bằng cách khảo sát
lớp EditingCommands).

Hình 7.2. Thêm ToolBar có 3 chế độ hiển thị chữ


Dưới đây là đoạn mã XAML đầy đủ cho phép ta xây dựng một hộp soạn
thảo văn bản có thể thay đổi được kiểu chữ (đậm, nghiêng, gạch chân):

67
Hình 7.3. Kết quả hiển thị màn hình soạn thảo đơn giản giống NotePad

Hình 7.4. Kiểm tra điền đúng các từ lỗi tiếng Anh

Câu hỏi ôn tập và bài tập

68
69
BÀI 8: TẠO MENU
Mã bài: 24.08
Giới thiệu:
Thực đơn (Menu) và thanh công cụ (Toolbar) là một trong những thành
phần quan trọng của cửa sổ, chúng chứa đựng các chức năng chính của chương
trình mà người dùng có thể thực hiện. Thanh thực đơn chứa hầu hết tất cả chức
năng chính của chương trình, tổ chức theo dạng phân cấp, trong khi thanh công
cụ thường chứa một số chức năng thiết yếu mà người dùng hay quan tâm dưới
dạng các biểu tượng hình ảnh để người dùng có thể thao tác một cách nhanh
chóng.
Mục tiêu:
- Trình bày công dụng các mục trong menu
- Thiết kế các mục cho menu
- Xử lý sự kiện cho các mục menu
- Đảm bảo an toàn cho người và thiết bị
Nội dung chính:
8.1. Xây dựng menu và các mục đơn giản
Thực đơn (Menu) là điều khiển gồm nhiều phần tử được tổ chức dưới
dạng phân cấp. Thanh thực đơn thường nằm trên đỉnh cửa số (dưới thanh tiêu
đề). Các phẩn tử thực đơn (Menu Item) xuất hiện trên thanh thực đơn còn được
gọi là Menu Item mức đỉnh. Mỗi Menu Item mức đỉnh có thể chứa nhiều Menu
Item cấp dưới (Sub Menu) hoặc được gắn trực tiếp với các bộ quản lý sự kiện
(Event handler) như sự kiện Click hay các lệnh của hệ thống được xây dựng
sẵn (như Copy, Cut, Paste,..). Tương tự như vậy, mỗi Menu Item cấp dưới lại
có thể chứa nhiều Menu Item cấp dưới của chính nó.

Khi một Menu Item chứa các Menu Item cấp dưới thì thường được gọi là
Popup Menu, các Menu Item cấp dưới sẽ xuất hiện khi người dùng nhấn chuột
lên Popup Menu. Nếu Menu Item được gắn trực tiếp với với bộ quản lý sự kiện
hay một lệnh của hệ thống thì được gọi là Command Menu, nó sẽ thực thi một

70
câu lệnh mong muốn khi người dùng nhấn chuột hoặc nhấn phím tắt (ký tự trên
bàn phím gắn với Menu Item) để chọn nó.

Hình 8.1. Ví dụ về Menu


Ta sẽ tìm hiểu từng bước xây dựng và sử dụng menu bắt đầu từ Menu với
các Menu Item đơn giản, tiếp đến là các Menu Item có trạng thái (Checked,
UnChecked) và Menu Item có biểu tượng hình ảnh.

Hình 8.2. Hiển thị điều khiển Menu

71
Đặt tên Menu

Thêm các đối tượng


con vào Menu

Hình 8.3. Đặt tên và tạo các Menu con

72
Danh sách các mục
Tiêu đề hiển thị mục
con
con của Menu

Chọn lưa vào thêm


mục con
Tạo thêm mục con
của các mục Menu

Hình 8.4. Màn hình thêm các Menu con và cách thức làm việc
Đoạn code XAML để tạo một Menu đơn giản:

73
Thanh Menu được bắt đầu bằng thẻ <Menu> và kết thúc bằng thẻ đóng
</Menu> . Có nhiều thuộc tính của thẻ này, trong ví dụ trên thì
Height="26" : Chiều cao menu là 26 pixel.
Name="menu1" : Tên của menu là menu1. Tên menu được mã trình
C# sử dụng để quản lý nó.
VerticalAlignment="Top" : Menu được căn để nằm bên trên của
Grid chứa nó.
Các Popup Menu được tạo bởi thẻ <MenuItem> và kết thúc bằng thẻ
đóng </MenuItem>.
Giữa cặp thẻ này là các thẻ <MenuItem> khác để tạo nên các Menu Item cấp
dưới của nó.
Các Command Menu thì được tạo bởi thẻ <MenuItem/>, không có
thẻ đóng. Một số thuộc tính cơ bản của Menu Item bao gồm

Header="…": Tiêu đề hay nhãn của Menu Item. Dấu gạch dưới đặt
trước ký tự sẽ được sử dụng làm phím tắt khi kết hợp với phím Alt để gọi
Menu Item bằng bàn phím. Trong ví dụ này thì ký tự 1 được dùng làm phím tắt
cho Menu Item “Thực đơn 1”, ký tự được dùng làm phím tắt sẽ được hiển thị
với dấu gạch chân khi người dùng nhấn phím Alt để mở Menu.
Name="…": Tên của Menu Item, cần thiết cho mã trình C# có thể can
thiệp vào Menu Item.
ToolTip="…": Lời chú thích cho Menu Item khi di chuột qua.
Đối với các Command Menu, có hai cơ chế thực thi lệnh khi chọn Menu.
Nếu muốn gắn Command Menu với các lệnh có sẵn của hệ thống như: Copy,
Cut, Paste,.. thì ta sử dụng thuộc tính Command của Menu Item. Ví dụ, lệnh
<MenuItem Header="_Copy"
Command="ApplicationCommands.Copy"/> làm cho Menu Item
Copy này sẽ thực hiện công việc copy dòng văn bản đang được chọn trong cửa
sổ vào.

74
Hình 8.4. Màn hình kết quả khi thực thi

75
8.2. Tạo các Menu có trạng thái Checked/Unchecked
Khi làm việc với Menu, đôi khi ta có những chức năng với đặc thù có hai
trạng thái On/Off. Ví dụ như chương cần có một Menu Item để làm cho một
Textbox hiển thị ở dạng chữ đậm và chữ thường, người dùng mong muốn
Menu Item thể hiện được trạng thái On/Off tương ứng với kiểu chữ (chữ
đậm/chữ thường) trên Textbox. Điều khiển Menu của WPF cung cấp cho
chúng ta loại Menu Item với hai trạng thái Checked và UnChecked.
Để tạo ra Menu Item có trạng thái, ta sử dụng thuộc tính
IsCheckable="True" của Menu Item.

Hình 8.1. Màn hình để chọn thêm một lớp mới vào Project

Hình 8.2. Màn hình đặt tên cho lớp đối tượng

76
Hình 8.3. Màn hình làm việc của cửa sổ lớp đối tượng được tạo
8.3. Tạo mục Menu có biểu tượng hình ảnh
Với các ứng dụng xây dựng trên nền .Net 2.0, công việc xây dựng Thực
đơn và Thanh công cụ với biểu tượng hình là khá đơn giản, có thể sử dụng công
cụ thiết kế giao diện trực quan. Ví dụ, muốn tạo menu có biểu tượng hình ảnh
(icon), chúng ta thêm Menu Trip vào form, sau đó thêm các mục cho thực đơn
(Menu Item). Nhấn chuột phải lên từng mục và chọn “Set Image” là thành
công. Tuy nhiên, khi xây dựng ứng dụng WPF, không có mục chọn “Set
Image” khi nhấn chuột phải vào một mục trong thực đơn. Chúng ta phải nạp
các tệp hình ảnh, biểu tượng và tài nguyên (Resource) của ứng dụng và viết một
số lệnh XAML để gắn biểu tượng cho Menu Item.
Nạp các tệp hình ảnh, biểu tượng vào tài nguyên của ứng dụng.

i. Trên thanh thực đơn Visual Studio, chọn Project → Properties sẽ hiện ra
bảng cài đặt các thông số cài đặt cho ứng dụng.

ii. Chọn mục resources.

iii. Trong mục Add Resource chọn Add Existing File nếu đã có sẵn File biểu
tượng hình ảnh trên máy hoặc chọn New Images hay Add New Icon tùy
ý.

77
iv. Chú ý, sau khi thêm được các File hình ảnh biểu tượng vào tài nguyên,
để các điều khiển trên cửa sổ như Menu, Toolbar sử dụng được
chúng, ta phải thiết lập thuộc tính 'Build Action : Resource' và
'Copy to Output Directory : Do not copy'.

Như vậy, chúng ta đã xây dựng thành công thanh menu với các biểu
tượng đẹp mắt hay menu với trạng thái Checked/UnChecked cũng như biết
cách gắn các hàm xử lý sự kiện cho các menu. Phần tiếp theo ta sẽ tìm hiểu về
thanh công cụ.

Bảng 8.1. Bảng mô tả các từ khóa định nghĩa lớp

Từ khóa Giải thích

Public Truy xuất mọi nơi

Protected Truy xuất trong nội bộ lớp hoặc trong các lớp con

Internal Truy xuất trong nội bộ chương trình (Assembly)

Truy xuất nội trong chương trình (assembly) và


protected internal
trong các lớp con

private (mặc định) Chỉ được truy xuất trong nội bộ lớp
Ví dụ: Khai báo một lớp có tên là Box gồm các thuộc tính: chiều dài, chiều rộng,
chiều cao.

78
Khai báo và khởi tạo thành viên thuộc tính (biến) tương tự cách khai báo biến
thông thường nhưng có sử dụng thêm Access Modifiers để quy định cấp
độ truy cập.

Câu hỏi ôn tập và bài tập


1. Tạo lớp đối tượng sinh viên bao gồm các thông tin: masv (mã sinh viên),
tennv (tên sinh viên), ngaysinh (ngày sinh), diachi (địa chỉ)
2. Tạo lớp đối tượng đồng hồ bao gồm các thông tin: thoigian, gio, phut, giay.
3. Tạo lớp đối tượng sản phẩm bao gồm các thông tin: masp (mã sản phẩm),
tensp (tên sản phẩm), gia (giá), ngaynhap (ngày nhập), ngayxuat (ngày xuất).

79
BÀI 9 : TẠO TOOLBAR
Mã bài: 24.09
Giới thiệu:
Thanh công cụ (Toolbar) là thanh chứa các chức năng dưới dạng các dãy
hình ảnh biểu tượng, mỗi biểu tượng gắn với một mục chức năng cụ thể. Thông
thường các Toolbar chứa những chức năng thiết yếu mà người dùng hay quan
tâm nhất, bởi vì thanh Toolbar có ưu điểm là dễ dàng thao tác. Một cửa số có
thể có một hoặc nhiều thanh Toolbar. Trong phần này ta tìm hiểu phương pháp
xây dựng thanh Toolbar với các nút chức năng thông thường và các nút chức
năng có trạng thái (Checked/UnChecked).
Mục tiêu:
- Biết công dụng các mục trong toolbar
- Thiết kế các mục cho toolbar
- Xử lý sự kiện cho các mục toolbar
- Đảm bảo an toàn cho người và thiết bị
Nội dung chính:

9.1. Tạo nút công cụ đơn giản


Ví dụ:

Hình 9.1. Màn hình hiển thị các ToobBar trong phần mềm

Hiển thị của ToolBar trên điều khiển ToolBox

Hình 9.2. Điều khiển ToolBar

80
Chúng ta bắt đầu tìm hiểu các bước xây dựng thanh Toolbar với các nút
bấm đơn giản như ví dụ minh họa ở hình 9.3. Thanh công cụ bao gồm năm nút:
Copy , Cut, Paste thực hiện các chức năng có sẵn của hệ thống, Nút A và a gắn
với hàm xử lý sự kiện tự xây dựng, làm nhiệm vụ tăng/giảm cỡ chữ của
Textbox bên dưới.

Hình 9.3. Kết quả ví dụ về ToolBar


Cần chuẩn bị các hình ảnh để tạo các điều khiển ToolBar

Hình 9.4. Cây thư mục để lưu trữ hình ảnh của Project

81
Thanh công cụ được xây dựng bằng đoạn mã XAML sau:

Mã XAML tạo thanh công cụ được được bắt đầu bằng thẻ <ToolBar>
và kết thúc bằng thẻ đóng </ToolBar>.
Các nút lệnh (Button) của thanh công cụ được tạo bởi thẻ <Button> và
kết thúc bằng thẻ đóng </Button>.
Name=" …": Tên của Button, cần thiết cho mã trình C# có thể can thiệp
vào Button.
ToolTip="…": Lời chú thích cho Button khi di chuột qua.
Có hai cơ chế thực thi lệnh khi chọn nút lệnh trong Toolbar.
Nếu muốn gắn nút lệnh với các lệnh có sẵn của hệ thống như: Copy, Cut,
Paste,.. thì ta sử dụng thuộc tính Command của Button. Ví dụ, lệnh <Button
Height="23" Name="button1" Width="23"
Command="ApplicationCommands.Copy" ToolTip="Copy văn
bản"> làm cho nút lệnh Copy này sẽ thực hiện công việc copy dòng văn
bản đang được chọn trong cửa sổ vào bộ nhớ đệm. Chú ý, các lệnh của hệ
thống bắt đầu bằng ApplicationCommands.
Nếu muốn gắn nút lệnh với các hàm xử lý sự kiện tự định nghĩa thì sử
dụng thuộc tính Click của Button. Ví dụ, <Button Height="23"
Name="button4" ToolTip="Tăng cỡ chữ" Width="23"
Click="IncreaseFont_Click"> để yêu cầu khi chọn "button4"
thì sẽ gọi hàm IncreaseFont_Click.

82
Giữa cặp thẻ <Button> và </Button> là thẻ <Image
Source="Resources/Copy.png" Width="16" Height="16"
HorizontalAlignment="Left" /> để định nghĩa hình ảnh biểu tượng
của nút bấm.
Thẻ <Separator/> dùng để tạo ra vạch phân cách giữa cách nút bấm.
Lập trình cho 2 nút tăng giảm cỡ chữ A, a như sau:

Sau khi lập trình được các chức năng của nút Tăng/Giảm cỡ chữ
Giảm cỡ chữ của
Textbox bên dưới

Tăng cỡ chữ của


Textbox bên dưới

Hình 9.5. Kết quả về ToolBar

9.2. Tạo nút công cụ trạng thái


Ngoài các nút bấm thông thường, thanh công cụ còn cho phép tạo ra các
nút bấm có trạng thái, khi ở trang thái được chọn (Checked) thì sẽ có màu nền

83
khác và có đường viền để người dùng có thể nhận biết được trạng thái của nút
đó.

Hình 9.6. Kết quả ví dụ về ToolBar dạng CheckBox

Khác với các nút lệnh thông thường được tạo bởi thẻ <Button>
và kết thúc bằng thẻ đóng </Button>, các nút lệnh có trạng thái được tạo nên
bởi thẻ <CheckBox Name="check1" ToolTip="Chữ đậm"
Checked="Bold_Checked" Unchecked="Bold_Unchecked"> và
kết thúc bằng thẻ đóng </CheckBox>.
Nút lệnh có trạng thái phát sinh hai sự kiện Checked và Unchecked,
tương ứng với trạng thái của nút là được chọn hay bỏ chọn khi người dùng nhấn
nút. Trong ví dụ trên, khi nút check1 được chọn thì hàm Bold_Checked
được gọi và nút check1bỏ chọn thì hàm Bold_Unchecked được gọi. Hai
hàm này do ta tự xây dựng với mã lệnh như sau.
Mã nguồn minh họa của hai hàm xử lý sự kiện nhấn nút check1,check2:

84
Kết quả chương trình:

Hình 9.7. Kết quả sau khi lập trình nút B,I dạng CheckBox
Câu hỏi ôn tập và bài tập
1. Trên thanh Menu, các Menu Item mức đỉnh chỉ có thể là Popup Menu?
A. Đúng
B. Sai
2. Menu Item mức dưới của một Popup Menu cũng có thể là một Popup Menu?
A. Đúng
B. Sai
3. Thuộc tính nào sau đây của Menu được dùng để gán nhãn (tiêu đề) cho
Menu?
A. Title
B. Header
C. Text
D. Tooltip

85
4. Các thuộc tính được có thể được sử dụng để gán lệnh cho một Menu Item
(Chọn nhiều)
A. Command
B. Click
C. OnClick
D. Checked và UnChecked
5. Thanh công cụ được phép nằm ở vị trí nào trên cửa sổ
A. Nằm ngang.
B. Nằm dọc
C. Được phép nằm cả theo chiều dọc và chiều ngang.
6. Những thẻ nào sau đây được dùng để tạo các nút trên thực đơn (Chọn nhiều):
A. <Button>
B. <Checkbox>
C. <ToolBar Item>

86
BÀI 10: TẠO CONTEXTMENU
Mã bài: 24.10
Giới thiệu:
Thực đơn ngữ cảnh (Context Menu) là loại thực đơn gắn với một điều
khiển cụ thể nào đó, chẳng hạn như một nút bấm hay một hộp soạn thảo,... Khi
người dùng nhấn chuột phải vào điều khiển có gắn thực đơn ngữ cảnh thì thực
đơn ngữ cảnh của điều khiển đó sẽ hiện ra và cho phép người dùng chọn công
việc mong muốn từ thực đơn.
Mục tiêu:
- Biết công dụng của ContextMenu
- Thiết kế giao diện có ContextMenu
- Kết hợp ContextMenu với control
- Xử lý sự kiện cho các mục trong ContextMenu
- Đảm bảo an toàn cho người và thiết bị.
Nội dung chính:

10.1. Context Menu riêng biệt


Thực đơn ngữ cảnh riêng biệt là thực đơn ngữ cảnh gắn với một điều
khiển cụ thể, các trạng thái của menu này chỉ dành riêng cho điều khiển chứa
nó sử dụng. Mã lệnh tạo thực đơn ngữ cảnh loại này đặt trực tiếp bên trong cặp
thẻ của điểu khiển chứa nó (như minh họa ở đoạn mã XAML trên). Xem ví dụ
minh họa ở hình 10.1, minh họa hai nút bấm, mỗi nút có một thực đơn ngữ
cảnh riêng. Khi chọn Menu “Đậm” của nút nào thì nội dung của nút đó hiển thị
dạng chữ đậm và đồng thời Menu tương ứng cũng ở trạng thái Checked và
ngược lại. Trạng thái Checked của mục “Đậm” của menu ngữ cảnh thuộc nút
bấm 1 không ảnh hưởng tới thực đơn của nút bấm 2.

87
Hình 10.1. Mẫu về Context Menu

Trong đoạn mã trên, ta có hai nút bấm với nhãn là “Nút bấm 1” và “Nút
bấm 2”, mỗi nút bấm có một thực đơn ngữ cảnh riêng.
Thực đơn ngữ cảnh của nút bấm được bắt đầu bằng
<Button.ContextMenu> và kết thúc bằng </Button.ContextMenu>.
Trong cặp thẻ này là cặp thẻ <ContextMenu> và </ContextMenu>.
Trong cặp thẻ <ContextMenu> và </ContextMenu> chứa các thẻ
<MenuItem> định nghĩa các mục của thực đơn.
Các mục thực đơn của thực đơn ngữ cảnh hoạt động tương tự như thư
đơn thông thường được đề cập ở bài trước.

88
89
10.2. Context Menu chia sẽ (Shared Context Menu)
Thực đơn ngữ cảnh chia sẻ là loại thực đơn ngữ cảnh có thể gắn với
nhiều điều khiển khác nhau. Khi một mục trên thực đơn ngữ cảnh của một điều
khiện được Checked thì tất cả các điều khiển khác cũng chia sẻ trạng thái này.
Ví dụ sau đây minh họa bốn điều khiển gồm hai Button và hai CheckBox
cùng chia sẻ chung một thực đơn ngữ cảnh, khi Check vào mục đầu tiên của
thực đơn ngữ cảnh trên một Button hay một CheckBox thì mục tương ứng của
các thực đơn ngữ cảnh trên các Button hay CheckBox khác cũng có trạng thái
Check tương ứng.

Hình 10.1. Ví dụ Menu Shared ContextMenu


Đoạn mã XAML để tạo menu ngữ cảnh:

90
Khác với thực đơn ngữ cảnh thông thường, vị trí câu lệnh tạo thực đơn
ngữ cảnh được không nằm giữa cặp thẻ của các điều khiển chứa nó mà được
khai báo dưới dạng tài nguyên chung của Window.

Thuộc tính x:Key dùng để khai báo tên của ContextMenu, sẽ được dùng
để gán cho các điều khiển muốn sử dụng ContextMenu này. Các điều khiển sẽ
gắn ContextMenu nhờ thuộc tính
ContextMenu="{DynamicResource ContextMenuChiase}".

Chú ý, phải đặt giá trị cho x:Shared="True" thì ContextMenu này
mới có thể được chia sẻ cho các điều khiển. Nếu đặt là x:Shared="False"
thì các điều khiển vẫn sử dụng được MenuContext này, nhưng mỗi điều khiển
có một thể hiện riêng của ContextMenu (không chia sẻ chung).

91
Câu hỏi ôn tập và bài tập
1. Trong các dòng mã lệnh sau đây, mã lệnh nào cho phép tạo và hiển thị một
đối
tượng Windows Form mới có tên là Form1
a) Form1 frm = new Form1;
frm.Show();
b) Form Form1 = new Form();
Form1.Show();
c) Form1 frm ;
frm.Show();
d) Form frm;
frm.Show();
e) Form Form1 = new Form();
Form1.ShowDialog();
2. Trong các thuộc tính sau, thuộc tính nào dùng để thiết lập nội dung hiển thị
trên
thanh title bar và thuộc tính nào dùng để thiết lập màu nền của form.
a) Thuộc tính Text và ForeColor
b) Thuộc tính Display và BackColor
c) Thuộc tính Text và BackColor
private void Form1_Click(object sender, EventArgs e)
{
//Tạo đối tượng lớp Form
Form Form2 = new Form();//Thiết lập tiêu đề trên titlebar
của form
Form2.Text = “Giao diện Form 2”;
//Thiết lập vị trí hiển thị form
Form2.StartPosition = FormStartPosition.CenterScreen;
//Thiết lập màu nền cho form

92
Form2.BackColor = Color.CadetBlue;
//Kiểm tra giá trị trả về của phương thức ShowDialog()
//nếu giá trị trả về là DialogResult.Cancel thì Form2
//đã đóng, tiến hành đóng Form1 bằng phương thức
//Close()
if (Form2.ShowDialog() == DialogResult.Cancel)
{
this.Close();
}
}
d) Thuộc tính Display và ForeColor
3. Các thuộc tính sau, thuộc tính nào cho phép thiết lập form trở thành
MdiForm
a) IsMdiContainer
b) MdiParent
c) MdiContainer
d) ParentForm
4. Các thuộc tính sau, thuộc tính nào cho phép thiết lập form trở thành Child
Form
a) IsMdiContainer
b) MdiParent
c) MdiContainer
d) ParentForm
5. Trong các sự kiện sau, sự kiện nào sẽ phát sinh khi form đã đóng
a) FormClosed
b) FormClosing
c) ClosedForm
d) ClosingForm
e) Load
f) Click
6. Xây dựng form có dạng hình tam giác như hình 2.21

93
Hình 10.12. Thiết kế form dạng tam giác
7. Thiết kế giao diện chương trình hiển thị thời gian như sau:

Hình 10.12. Thiết kế form hiển thị MenuStrip


Yêu cầu:
Menu Chức năng: Chức mục Thoát dạng MenuItem. Khi người dùng nhấn
chuột trái
vào Thoát hoặc nhấn tổ hợp phím Ctrl + T sẽ thoát chương trình.
Menu Nội dung hiển thị: Dạng ComboBox. ComboBox chứa hai mục chọn:
Hiển thị thời gian: Giúp hiển thị giờ phút giây trên label lblHienThi
Hiển thị ngày tháng: Giúp hiển thị ngày tháng năm trên label lblHienThi

94
BÀI 11: TẠO STATUSBAR
Mã bài: 24.11
Giới thiệu:
Thanh công trạng thái là thanh nằm ngang, bên dưới đáy cửa sổ, gồm
nhiều phần tử nhằm thể hiện thông tin về các trạng thái hoạt động của ứng dụng.
Mỗi phần tử có thể là một văn bản, một biểu tượng hay một thanh tiến trình.
Mục tiêu:
- Biết công dụng của StatusBar
- Thiết kế và sử dụng StatusBar
- Sử dụng StatusBar đúng mục đích
- Đảm bảo an toàn cho người và thiết bị
Nội dung chính:

11.1. Phần tử văn bản


Để bắt đầu tìm hiểu từng bước xây dựng thanh trạng thái, ta tìm hiểu mã
lệnh XAML tạo thanh trạng thái đơn giản với các phần tử dạng văn bản.
Thanh trạng thái đơn giản, chỉ gồm một phần tử dạng văn bản.

Thanh trạng thái đuợc xây dựng bằng đoạn mã XAML sau:

95
Hình 11.1. Kết quả điều khiển Status Bar
Thanh trạng thái gồm nhiều hơn một phần tử. Ví dụ, thanh trạng thái
gồm hai mục Ready và Set

96
Hình 11.2. Kết quả điều khiển Status Bar gồm 2 StatusBarItem
Ởví dụ trên phần tử thứ hai nằm ngay bên cạnh phần tử thứ nhất, nếu
muốn phần tử thứ nhất có rộng lớn hơn và phần tử thứ hai được căn bên phải
cửa sổ cho thuận tiện (như hình dưới) ta phải sử dụng kỹ thuật tạo layout (bố
cục) trong thanh trạng thái để phân chi thanh trạng thái thành các vùng mong
muốn và đặt các phần tử cần thiết vào các vùng tương ứng

Ở đoạn mã XAML sử dụng thẻ <StatusBar.ItemsPanel> và


</ItemsPanelTemplate> để định nghĩa bố cục của các phần tử trong

97
thanh trạng thái. Trong đó là cặp thẻ <ItemsPanelTemplate> và
</ItemsPanelTemplate>. Kế tiếp, sử dụng thẻ <Grid> để định nghĩa các
vùng hiển thị kiểu ô lưới. Trong ví dụ này, lưới bao gồm một dòng và hai cột.
Cột thứ nhất có độ dài tự co dã đễ chiếm toàn bộ không gian trống nhờ thuộc
tính Width="*". Cột thứ hai có độ dài bằng độ dài nội dung mà nó chứa nhờ
thuộc tính Width="Auto".
Phần tử thứ nhất được gắn với cột thứ đầu tiên của lưới
(Grid.Column="0").

Cột thứ hai được gắn với cột thứ hai của lưới (Grid.Column="1").

11.2. Phần tử Progress Bar


Đôi khi, trên thanh trạng thái ta muốn thể hiện trạng thái thực hiện của một công
việc nào đó, ta có thể đưa thanh tiến trình vào một phần tử trên thanh trạng thái

Mã lệnh minh họa thanh trạng thái trên như sau:

98
Ở ví dụ trên, ta đặt thanh trạng thái vào mục thứ hai của thanh trạng thái:

11.3. Phần tử hình ảnh

99
Ở ví dụ trên, ta đặt thanh trạng thái vào mục thứ tư của thanh trạng thái,
thuộc tính Grid.Column bắt đầu với chỉ số = 0.

11.4. Mã lệnh tổng hợp


Đoạn mã XAML để thiết kế tổng hợp thanh Status Bar
<Window x:Class="Bai4.StatusBar"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Bai4"
mc:Ignorable="d"
Title="StatusBar" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="30"/>
</Grid.RowDefinitions>
<StackPanel Grid.Row="0" >
<TextBlock FontSize="12" TextWrapping="WrapWithOverflow"
Margin="196,15,184,30" Height="51"><Run Text="Ví dụ minh họa đặt các phần tử trên
thanh trạng thái. Mỗi phần tử có thể là văn bản, ảnh hay thanh tiến
trình."/></TextBlock>

</StackPanel>
<StatusBar Grid.Row="1">
<StatusBar.ItemsPanel>
<ItemsPanelTemplate>

100
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="20"/>
</Grid.ColumnDefinitions>
</Grid>
</ItemsPanelTemplate>
</StatusBar.ItemsPanel>
<StatusBarItem Grid.Column="0">
<TextBlock>Ready</TextBlock>
</StatusBarItem>
<StatusBarItem Grid.Column="1">
<ProgressBar Value="30" Width="80" Height="18"/>
</StatusBarItem>
<StatusBarItem Grid.Column="2">
<TextBlock>Set</TextBlock>
</StatusBarItem>
<StatusBarItem Grid.Column="3">
<Image Source="Hinhanh/Home.png" Width="16"
Height="16"/>
</StatusBarItem>
</StatusBar>

</Grid>
</Window>

Câu hỏi ôn tập và bài tập


1. Context Menu xuất hiện khi nhấn chuột nào lên điều khiển? :

A. Chuột trái
B. Chuột phải

101
2. Context Menu có thể chứa cả Command Menu Item và Popup Menu Item? :
A. Đúng
B. Sai
3. Câu lệnh XAML định nghĩa thực đơn ngữ cảnh phải nằm trong cặp thẻ định
nghĩa điều khiển chứa thực đơn?
A. Đúng
B. Sai
4. Thực đơn ngữ cảnh có thể chia sẻ cho nhiều điều khiển dùng chung?
A. Đúng
B. Sai
5. Thanh trạng thái chỉ được phép chứa một phần tử trạng thái:
A. Đúng
B. Sai
6. Thanh trạng thái có thể chứa những các phần tử thuộc loại nào?
A. Văn bản.
B. Hình ảnh.
C. Các điều khiển khác như Button, ProgressBar,..
D. Cả ba loại trên

102
BÀI 12: XỬ LÝ SỰ KIỆN VÀ DÙNG LỆNH
Mã bài: 24.12
Giới thiệu:
Các bài giảng trước chủ yếu giới thiệu về các thành phần trực quan trong
WPF và việc làm thế nào để tạo lập giao diện đồ hoạ kết hợp những thành phần
đó. Tuy nhiên, một giao diện đồ họa không chỉ mang tính thẩm mỹ cao mà còn
phải cho phép người dùng tương tác với các thành phần trên đó. Việc tương tác
với ứng dụng của người dùng thông qua giao diện đồ hoạ có liên quan nhiều
trên việc viết mã lệnh xử lý sự kiện (events) và lệnh (commands). Mặc dù các
khái niệm này đã được đề cập sơ bộ trong các bài giảng trước, bài giảng này
giới thiệu một cách có hệ thống hơn về hai khái niệm quan trọng này trong
WPF.
Mục tiêu:
- Biết công dụng của sự kiện và lệnh
- Xứ lý các sự kiện của control
- Lập trình cho phép người dùng tương tác với giao diện
- Kết hợp sự kiện và lệnh
- Đảm bảo an toàn cho người và thiết bị
Nội dung chính:

12.1. Xử lý sự kiện
Mỗi khi nhắp chuột vào một nút bấm hay gõ dòng văn bản nào đó vào
một form tức là đang sử dụng sự kiện (events). Trong lập trình, có thể định
nghĩa sự kiện là một hành động được phát động bởi người dùng, bởi một thiết bị
như đồng hồ đếm (timer) hay bàn phím, hoặc thậm chí là bởi hệ điều hành, tại
những thời điểm phần lớn là không theo chu trình nhất định. Ví dụ, với một
thiết bị định vị con trỏ như chuột, hành động nhắp phím chuột sẽ gây nên sự
kiện “nhắp chuột”. Mỗi khi một sự kiện xảy ra, thông thường dữ liệu liên quan
đến sự kiện đó được thu thập và chuyển nó tới một đơn vị xử lý sự kiện (event
handler) để xử lý tiếp. Cũng có khi, sự kiện bị bỏ qua hay chuyển tới nhiều hàm
xử lý sự kiện một lúc nếu những hàm xử lý này cùng đồng thời lắng nghe sự

103
kiện đó. Dữ liệu tương ứng với một sự kiện ít nhất xác định loại sự kiện, nhưng
đôi khi cũng bao gồm các thông tin khác như sự kiện xảy ra tại thời điểm nào,
đối tượng nào phát động nó...
Thông thường, ta hầu như không suy nghĩ về việc sự kiện xảy ra như thế nào, ví
dụ làm sao để máy tính nhận biết chuột trái được nhắp, hay một phím trên bàn
phím được bấm… Lý do là vì các chi tiết ở mức thấp này đã được framework
đồ hoạ trong máy tính xử lý. Ngay cả đối với người phát triển, công việc của ta
với sự kiện phần lớn là xử lý phần bề nổi của nhiều vấn đề ở phía sau mỗi sự
kiện. Ngay cả trong trường hợp đó, có rất nhiều phần “bề nổi” cần được xem
xét. Trong phần này, trước hết ta tìm hiểu cơ chế xử lý sự kiện trong WPF.
12.1.1. Đơn vị xử lý sự kiện
Mỗi đơn vị xử lý sự kiện (event handler) đơn giản là một phương thức
(hàm) nhận đầu vào từ một thiết bị như chuột hay bàn phím và thực hiện một
việc nào đó để phản ứng lại với một sự kiện xảy ra trên thiết bị đó. Ví dụ sau
đây minh hoạ đoạn mã lệnh C# là một đơn vị xử lý sự kiện có tên
ButtonOkClicked có tác dụng xử lý sự kiện nút chuột được bấm:

Để đễ hiểu, ta dùng từ “hàm xử lý sự kiện” với nghĩa tương đương “đơn


vị xử lý sự kiện”
Thực chất, có hai bước cần thực hiện để xử lý một sự kiện:
- Liên kết đơn vị xử lý sự kiện với điều khiển (nút bấm, trường văn bản, thực
đơn…), nơi sự kiện tương ứng được phát động.
- Viết mã lệnh trong đơn vị xử lý sự kiện để lập trình các công việc phản ứng
lại với sự kiện.
Có hai cách để liên kết một sự kiện với một đơn vị xử lý sự kiện. Có thể dùng
(1) một môi trường phát triển tích hợp (IDE) như Expression Blend hoặc WPF
Designer của Visual Studio (cách trực quan); hoặc (2) viết mã lệnh trực tiếp
Cách trực quan

104
Để liên kết theo cách này, ta cần có các công cụ thiết kế giao diện GUI dành
cho WPF chẳng hạn như Expression Blend hoặc WPF Designer của Visual
Studio. Với các công cụ này, với mỗi phần từ UI trên giao diện ta có cửa sổ liệt
kế các sự kiện. Với mỗi sự kiện, ta có thể phân định đơn vị xử lý sự kiện bằng
cách khai báo tên hàm xử lý (không gồm đối số) bên cạnh sự kiện ta muốn bắt
và xử lý. Hình 12.1 minh hoạ việc khai báo hàm xử lý sự kiện ButtonOkClicked
ứng với sự kiện Click của nút bấm btnOK sử dụng Expression Blend.

Hình 12.1. Phân định trực quan hàm ButtonOkClicked xử lý sự kiện Click của
nút btnOK trên Expression Blend
Sau khi khai báo, ta nhấn Enter, môi trường sẽ tự động tạo sinh và
chuyển ta đến khuôn rỗng của hàm xử lý sự kiện có tên giống với tên ta đã đặt
cho đơn vị xử lý sự kiện khi khai báo, và với danh sách tham số ngầm định
tương ứng với loại sự kiện. Nhiệm vụ của người lập trình lúc này là viết mã
lệnh thực hiện các hành động phản ứng với sự kiện bên trong hàm xử lý này.
Trong ví dụ về nút bấm trên, khuôn dạng tự sinh của hàm xử lý sẽ là:

105
Khi nhìn lại mã XAML tương ứng, ta sẽ thấy WPF sử dụng XAML để
khai báo liên kết giữa sự kiện mà hàm xử lý sự kiện như thế nào:

Như đã thấy, để gắn kết sự kiện Click với hàm xử lý ButtonOkClicked, ta


có thể khai báo Click="ButtonOkClicked" trong khai báo tạo lập nút
bấm trong mã XAML.
Cách viết mã lệnh trực tiếp
Ta cũng có thể liên kết sự kiện vào hàm xử lý bằng mã lệnh với kết quả
không đổi. Có thể tự hỏi tại sao không chọn cách trực quan ở trên. Một lý do cơ
bản là nếu ta muốn tạo ra các điều khiển một cách linh động, ví dụ sinh ra một
hay nhiều nút bấm trong thời gian chạy (runtime) chứ không phải tạo lập sẵn
trong thời gian thiết kế form (design-time), thì cách duy nhất để liên kết sự kiện
của các điều khiển đó vào hàm xử lý là thông qua mã lệnh. Xét ví dụ sau đây:
Giả sử ta có một nút bấm có tên là btnOK, và mục tiêu của ta là gắn kết
một sự kiện của nó với hàm xử lý mà chỉ dùng mã lệnh. Tất cả những việc phải
làm là chọn tên sự kiện tương ứng mà ta muốn bắt và liên kết nó với dòng lệnh
new RoutedEventHandler với đối số là tên của hàm xử lý của ta. Ví dụ:

Tiếp theo ta khai báo hàm xử lý với đối số tương ứng với sự kiện. Thông
thường mỗi loại sự kiện của mỗi loại điều khiển lại đòi hỏi hàm xử lý sự kiện
tương ứng với nó có chứa danh sách tham số xác định (có số lượng, thứ tự và
kiểu tham số xác định trước), mặc dù tên gọi của hàm xử lý có thể tuỳ ý. Nếu ta
sử dụng cách trực quan, cấu trúc của hàm xử lý sự kiện sẽ được tự động tạo ra.
Việc của ta chỉ là viết nội dung xử lý bên trong hàm xử lý. Trong trường hợp
viết mã lệnh, ta phải tự viết phần khai báo hàm xử lý, trong đó, cần tuân theo

106
quy tắc định nghĩa về cấu trúc tham số (số lượng, thứ tự, kiểu tham số) tương
ứng của sự kiện đó. Để biết được cấu trúc này, không gì khác ngoài việc tìm
đọc các tài liệu tham khảo về sự kiện tương ứng, mà MSDN là tài liệu đầy đủ
và chính xác nhất.
Trong ví dụ trên, phần nội dung hàm xử lý sự kiện Click trong mã C# sẽ
là:

Để ý rằng hàm xử lý sự kiện trong ví dụ chứa 2 tham số mà giá trị của


chúng sẽ được lấy từ sự kiện – sender tham chiếu đến đối tượng phát động sự
kiện (ở đây là nút bấm btnOK) và event (e) chỉ ra dạng tác động cụ thể để sự
kiện bị kích hoạt, chẳng hạn như bấm phím hay nhắp chuột...
Trong nhiều trường hợp, không cần phải quan tâm đến các tham số của hàm xử
lý sự kiện. Ví dụ, trong đoạn mã ví dụ ở trên, phần nội dung xử lý sự kiện
không hề dùng tới tham số sender lẫn tham số e. Tuy nhiên, sẽ có những trường
hợp trong đó, muốn sử dụng cùng một hàm xử lý ứng với nhiều sự kiện có cùng
bản chất hoặc cho một loại sự kiện của nhiều đối tượng cùng loại. Khi đó, ta
phải quan tâm đến điều khiển nào đã gửi sự kiện, lúc đó tham số sender và
event có thể sẽ hữu dụng.
12.1.2. Sự kiện có định tuyến
WPF mở rộng mô hình lập trình hướng sự kiện chuẩn của .NET, bằng
việc đưa ra một loại sự kiện mới gọi là sự kiện có định tuyến (routed event).
Loại sự kiện này nâng cao tính linh hoạt trong các tình huống lập trình hướng
sự kiện. Việc thiết lập và xử lý một sự kiện có định tuyến có thể thực hiện với
cùng cú pháp với một sự kiện “thường” (CLR event).
Cây trực quan:
Trước khi bàn luận thêm về sự kiện có định tuyến, một khái niệm quan
trọng cần biết đó là cây trực quan (visual tree). Một giao diện người dùng WPF
được xây dựng theo phương thức phân lớp, trong đó một phần tử trực quan
không có hoặc có các phần tử con. Cấu trúc phân cấp của các lớp phần tử trực

107
quan như thế trên một giao diện người dùng được gọi là cây trực quan của giao
diện đó. Ví dụ, xét giao diện được định nghĩa bằng đoạn mã XAML sau:

Kết quả hiển thị chương trình:

Hình 12.2. Kết quả tạo các nút lệnh theo thứ tự
Cây trực quan tương ứng sẽ là

Hình 12.3. Ví dụ về cây trực quan


Sự kiện có định tuyến là gì?
Về mặt chức năng, sự kiện có định tuyến là một loại sự kiện có thể kích
hoạt nhiều đơn vị xử lý sự kiện thuộc về nhiều điều khiển khác nhau trên cây
trực quan, chứ không chỉ trên đối tượng đã phát động sự kiện.

108
Một ứng dụng WPF điển hình thường chứa nhiều phần tử UI. Bất kể
được tạo ra bằng mã lệnh hay được khai báo bằng XAML, các thành phần này
tồn tại trong mối quan hệ kiểu cây trực quan với nhau - tạo nên các tuyến quan
hệ đi từ thành phần này tới thành phần kia. Theo các tuyến quan hệ đó, có ba
phương thức định tuyến sự kiện: lan truyền lên (bubble), lan truyền xuống
(tunnel) và trực tiếp (direct).
Lan truyền lên (bubble) là phương thức thường thấy nhất. Nó có nghĩa là
một sự kiện sẽ được truyền đi trên cây trực quan từ thành phần nguồn (nơi sự
kiện được phát động) cho tới khi nó được xử lý hoặc nó chạm tới nút gốc. Điều
này cho phép ta xử lý một sự kiện trên một đối tượng nằm ở cấp trên so với
thành phần nguồn. Ví dụ, có thể gắn một hàm xử lý sự kiện Button.Click vào
đối tượng Grid có chứa nút bấm thay vì gắn hàm xử lý đó vào bản thân nút
bấm. Sự kiện lan truyền lên có tên gọi thể hiện hành động của sự kiện, ví dụ:
MouseDown.
Sự kiện lan truyền xuống (tunnel) đi theo hướng ngược lại, bắt đầu từ nút
gốc và truyền xuống cây trực quan cho tới khi nó được xử lý hoặc chạm tới
thành phần gốc của sự kiện đó. Điều này cho phép các thành phần cấp trên có
thể chặn sự kiện và xử lý nó trước khi sự kiện đó chạm tới thành phần nguồn
(nơi dự định xảy ra sự kiện). Các sự kiện lan truyền xuống có tên được gắn
thêm tiền tố Preview, ví dụ, sự kiện PreviewMouseDown.
Sự kiện trực tiếp (direct) hoạt động giống như sự kiện thông thường trong
.NET Framework.
Chỉ có một đơn vị xử lý duy nhất sẽ được gắn với sự kiện trực tiếp.
Thông thường, nếu một sự kiện lan truyền xuống được định nghĩa cho
một sự kiện nào đó, đồng thời cũng sẽ có một sự kiện lan truyền lên tương ứng.
Trong trường hợp đó, sự kiện lan truyền xuống sẽ được phát động trước, bắt
đầu từ gốc và chạy xuống tìm kiếm hàm xử lý trên cây trực quan. Một khi nó đã
được xử lý hoặc chạm tới thành phần nguồn, sự kiện lan truyền lên sẽ được
phát động, lan truyền từ thành phần nguồn đi ngược lên để tìm tới hàm xử lý nó
trên cây trực quan. Sự kiện lan truyền lên hay xuống sẽ không ngừng lan truyền
vì một hàm xử lý nó được gọi. Do vậy, nếu ta muốn dừng quá trình truyền

109
xuống hoặc lên, ta phải đánh dấu “đã xử lý” cho tham số sự kiện truyền vào, cụ
thể:

Một khi ta đã đánh dấu “đã xử lý” cho sự kiện (e.Handled =


true), nó sẽ không được lan truyền tiếp nữa.

Trở lại ví dụ trên, nguồn của sự kiện Click là một trong những thành
phần nút bấm, và bất kể nút nào được bấm, nó sẽ trở thành thành phần đầu tiên
được phép xử lý sự kiện. Tuy nhiên, nếu không có đơn vị xử lý nào tương ứng
với sự kiện Click gắn với nút đó, thì sự kiện sẽ được lan truyền lên trên phần tử
cha của nút bấm, trong trường hợp này là StackPanel, rồi sau đó, lan truyền tới
Border... Nói cách khác, tuyến lan truyền sự kiện Click sẽ là:
ButtonStackPanelBorder...
Các tình huống cơ bản sử dụng sự kiện có định tuyến
Phần sau đây tổng kết những tình huống cần vận dụng khái niệm sự kiện
có định tuyến, và tại sao một sự kiện CLR điển hình là không đủ trong những
tình huống đó.
a. Bao đóng và kết hợp điều khiển

110
Nhiều điều khiển trong WPF có cấu trúc nội dung phức hợp. Ví dụ, ta có thể đặt
một hình ảnh bên trong một nút bấm, làm mở rộng cây trực quan của nút bấm.
Tuy nhiên, hình ảnh thêm vào không được phép phá vỡ cơ chế hit-testing, cơ
chế khiến nút bấm phản ứng với việc nhắp chuột vào trong nó, ngay cả khi
người dùng nhắp chuột vào những pixel là một phần của hình ảnh thêm vào.
b. Các điều khiển sử dụng cùng một đơn vị xử lý sự kiện
Trong Windows Forms, có trường hợp ta cần gán nhiều lần cùng một đơn
vị xử lý để xử lý các sự kiện thuộc vào nhiều thành phần khác nhau. Sự kiện có
định tuyến cho phép ta gán đơn vị xử lý chỉ một lần trong trường hợp đó. Như
trong ví dụ đã nêu trong đoạn mã XAML, sau đây là hàm xử lý tương ứng:

c. Xử lý lớp:

Sự kiện có định tuyến cho phép một đơn vị xử lý tĩnh (static) được định
nghĩa trong lớp. Đơn vị xử lý lớp này có cơ hội xử lý một sự kiện trước khi một
đơn vị xử lý gắn với đối tượng cụ thể nào đó của lớp có thể.

d. Tham chiếu đến một sự kiện mà không bị hiện tượng phản xạ:
Các kỹ thuật markup và mã lệnh đòi hỏi phải có cách để định danh một
sự kiện. Một sự kiện có định tuyến tạo ra trường RoutedEvent như một định
danh, cung cấp một kỹ thuật định danh sự kiện mạnh mà không đòi hỏi hiện
tượng phản xạ tĩnh hoặc run-time.
Lợi ích của sự kiện có định tuyến

111
Cơ chế thông báo sự kiện kiểu định tuyến có nhiều lợi ích. Một lợi ích rất
quan trọng của sự kiện có định tuyến là một thành phần UI trực quan không cần
móc nối cùng một sự kiện trên tất cả các thành phần con trong nó, chẳng hạn sự
kiện MouseMove. Thay vào đó, nó có thể móc nối sự kiện này vào bản thân nó,
và khi con chuột di chuyển qua một trong các thành phần con của nó, sự kiện
này sẽ được lan truyền tới nó.

Một ưu điểm quan trọng khác của sự kiện có định tuyến là các thành
phần ở tất cả các mức trong cây trực quan có thể tự động thực thi mã lệnh để
phản ứng lại các sự kiện của các thành phần con của chúng, mà không cần các
thành phần con phải thông báo khi sự kiện xảy ra.
Một ví dụ đầy đủ về sự kiện có định tuyến
Form chỉ bao gồm một StackPanel chứa 2 Button và 1 TextBlock có tên
xác định. StackPanel được phân định bắt sự kiện Click trên hai nút bấm nằm
trong nó. Nhiệm vụ của đơn vị xử lý sự kiện Click là cho biết đối tượng nào đã
xử lý sự kiện Click, sự kiện Click phát ra từ loại đối tượng nào, tên gọi là gì
nào, và loại lan truyền định tuyến đã được thực hiện. Các thông tin trên được
đưa vào nội dung của TextBlock và hiển thị lên màn hình sau mỗi sự kiện
Click.

Đoạn mã XAML khai báo giao diện như sau:

Đoạn mã lệnh C# cho hàm HandleClick để xử lý sự kiện Click:

112
113
12.2. Lệnh
Ra lệnh (commanding) là một cơ chế nhập tin trong WPF cung cấp khả
năng xử lý đầu vào ở mức ngữ nghĩa hơn là xử lý đầu vào từ thiết bị. Các ví dụ
về command là các hành động Copy, Cut và Paste mà ta đã gặp ở nhiều ứng
dụng. Phần tiếp theo sẽ trình bày tổng quan về khái niệm này trong WPF.
Điểm khác biệt giữa lệnh và một đơn vị xử lý sự kiện đơn giản gắn với
một nút hay một đồng hồ đếm là: lệnh tách bạch giữa ngữ nghĩa cũng như
nguồn phát hành động với logic thực hiện hành động đó. Điều này cho phép
nhiều nguồn khác biệt nhau hoàn toàn có thể phát động cùng một logic lệnh,
đồng thời, cho phép tuỳ biến logic lệnh tuỳ vào các đối tượng bị tác động khác
nhau.
Ví dụ điển hình về lệnh là các hành động Copy, Cut và Paste, được thấy
ở rất nhiều ứng dụng. Ngữ nghĩa của các lệnh này là nhất quán với tất cả các
ứng dụng và lớp khác nhau (Copy - tạo bản sao từ đối tượng được chọn; Cut -
tạo bản sao rồi xoá bỏ đối tượng được chọn (cắt); Paste – Chèn đối tượng được
copy/cắt vào vị trị được chọn). Tuy nhiên, logic hành động lại tuỳ thuộc vào đối
tượng cụ thể mà ta tác động lên. Ví dụ, tổ hợp phím CTRL+X có thể phát động
lệnh Cut trên các lớp văn bản, các lớp hình ảnh và trên trình duyệt Web, nhưng
logic thực sự thực hiện hành động Cut lại được định nghĩa bởi đối tượng hoặc
ứng
dụng mà lệnh cắt tác động lên chứ không phải từ nguồn đã phát ra lệnh. Cụ thể
hơn, một đối tượng văn bản có thể cắt đoạn văn bản được chọn vào clipboard,
trong khi một đối tượng hình ảnh có thể cắt lấy vùng ảnh được chọn, nhưng

114
nguồn phát lệnh là như nhau - một tổ hợp phím hay một nút bấm trên thanh
công cụ.

Một cách đơn giản để sử dụng lệnh trong WPF là sử dụng một
RoutedCommand đã được định sẵn trong các lớp thư viện lệnh; sử dụng một
điều khiển có hỗ trợ sẵn xử lý lệnh đó và một điều khiển hỗ trợ sẵn khả năng
phát động lệnh. Trong ví dụ dưới đây, lệnh Paste là một trong những lệnh định
sẵn trong lớp ApplicationCommands. Điều khiển TextBox đã xây dựng sẵn khả
năng xử lý lệnh Paste. Và lớp MenuItem hỗ trợ khả năng phát động lệnh.

Ví dụ sau đây minh hoạ cách thức tạo lập một MenuItem để khi nhắp
chuột vào nó, lệnh Paste sẽ được phát động trên một TextBox, với giả thiết
là hộp TextBox đang nhận được Focus.

12.2.1. Hệ thống lệnh của WPF

12.2.2. Lệnh có định tuyến


Sự khác biệt giữa lệnh có định tuyến và sự kiện có định tuyến là cách mà
lệnh được dẫn đường từ nơi phát động lệnh (nguồn lệnh) tới nơi xử lý lệnh
(đích lệnh). Trong mô hình lệnh có định tuyến, sự kiện có định tuyến được sử
dụng dưới dạng các thông báo giữa giữa nguồn lệnh vào đích lệnh (thông qua
liên kết lệnh).

Trong một thời điểm nhất định, chỉ có một đơn vị xử lý lệnh (gắn với
đích lệnh) sẽ được thực sự kích hoạt (Đơn vị xử lý lệnh hoạt động). Đơn vị xử
lý lệnh hoạt động được xác định bằng việc kết hợp giữa vị trí của nguồn lệnh và
đích lệnh trên cây, và đâu là thành phần UI đang nhận được focus. Khi lệnh
được phát đi, sự kiện có định tuyến sẽ được sử dụng để gọi đến đơn vị xử lý
lệnh hoạt động, để hỏi xem lệnh này có được cho phép không (thông qua
phương thức CanExecute), cũng như thực hiện logic hành động (thông qua phát
động phương thức Executed).

115
Thông thường, nơi phát lệnh sẽ tìm liên kết lệnh giữa vị trí của nó trên
cây trực quan và nút gốc của cây trực quan. Nếu nó tìm thấy một liên kết lệnh
như thế, đơn vị xử lý lệnh tương ứng sẽ xác định lệnh này có được cho phép
thực hiện không. Nếu như lệnh được gắn với một điều khiển trên thanh công cụ
hay menu, thì một vài bước logic thêm sẽ được thực hiện để tìm dọc theo
đường đi trên cây trực quan từ nút gốc tơi phần tử đang nhận được focus để tìm
kiếm một liên kết lệnh.

Một điểm quan trọng cần hiểu về việc định tuyến trong lệnh có định
tuyến của WPF là một khi một đơn vị xử lý lệnh đã được kích hoạt, sẽ không có
đơn vị xử lý nào khác được gọi.

Để nắm rõ hơn về ưu điểm của việc sử dụng lệnh trong WPF ta xét ví dụ
sau:
Ta xét một form gồm một ListBox (có tên lsbCustomers) chứa danh
sách tên các khách hàng và một menu có chứa mục xoá Delete, có tác dụng xoá
mục được chọn trong danh sách. Ta
muốn chắc chắn rằng người sử dụng phải chọn tên khách hàng trong danh sách
trước khi có thể bấm mục xoá Delete trên menu.

Đoạn mã sau sẽ vô hiệu hoá mục Delete trên cơ sở có một mục được
chọn trong danh sách khách hàng hay không.

Đây là cách thông thường để đồng bộ hoá việc cho phép hay vô hiệu một
mục menu hay nút bấm ứng với một điều kiện nào đó. Để đạt mục tiêu đã nêu
của đầu bài, đoạn mã trên có thể được gọi trong đơn vị xử lý sự kiện
SelectionChanged của ListBox như sau:

116
Cách xử lý dựa trên sự kiện kiểu này là bình thường khi trên form chỉ có
một ListBox. Tuy nhiên, khi form trở nên phức tạp hơn, ví dụ chứa 2 ListBox,
khi đó việc xử lý theo cách trên trở nên phức tạp. Trở lại ví dụ, giả sử ta có
thêm một ListBox có chứa danh sách các mặt hàng (có tên lsbProducts).
Cả hai ListBox chứa tên khách hàng và tên mặt hàng đều chịu tác động
của mục Delete khi chúng nhận được focus và một trong các tên được chọn.
Trong trường hợp này, để xét xem mục Delete nên bị vô hiệu hoá hay không,
điều kiện kiểm tra trở nên phức tạp hơn:

Đồng thời, cũng yêu cầu thêm mã lệnh đối với việc xử lý sự kiện Click
lên mục Delete trên menu: Ta phải xác định ListBox nào bị tác động:

117
Hãy tưởng tượng nếu như form chứa khoảng 5 điều khiển cùng chịu tác
động của hành động Delete, phần mã lệnh xử lý sẽ trở nên phức tạp đến mức
nào. May mắn là WPF cung cấp một phương thức tốt hơn trong trường hợp như
vậy. Cơ chế lệnh trong WPF đơn giản hoá mã lệnh trong trường hợp này bởi nó
phân tách rõ giữa lệnh với phần triển khai lệnh (logic lệnh), cho phép ta liên kết
điều khiển với những lệnh cụ thể, như ta sẽ thấy trong tiếp theo.

Đây là đoạn mã lệnh tương đương cho ví dụ trên sử dụng Command


trong WPF.

Đoạn mã đầu phân định giá trị cho thuộc tính Command cho mục Delete
trên menu. Nó cũng gắn một liên kết lệnh vào ListBox danh sách khách hàng.
Trong trường hợp này, menu Delete là nguồn lệnh, và ListBox đóng vai trò là
đích lệnh. CommandBinding xác định hàm thực hiện đối với hai thuộc tính
CanExecute và Executed. CanExecute xác định khi nào lệnh Delete có thể được
thực hiện, trong khi Executed xác định thực hiện logic lệnh trên đích lệnh như
thế nào. Sau đây là mã lệnh cài đặt cho hai hàm này:

118
Kết quả hiển thị chương trình khi chưa chọn đối tượng nút lệnh Delete bị ẩn

Kết quả hiển thị chương trình khi chọn đối tượng nút lệnh Delete sáng lên

Kết quả hiển thị chương trình khi nhấp vào nút lệnh Delete đối tượng được chọn
bị xóa

Cho tới đây, ta chưa thấy được ưu điểm của cách tiếp cận này. Tuy nhiên,
trong trường hợp thêm vào một ListBox danh sách sản phẩm, lợi ích của
phương pháp sẽ thể hiện rõ hơn. Sau đây là đoạn mã XAML khai báo tạo lập
ListBox chứa danh sách sản phẩm:

119
Một lần nữa, ta chỉ cần cài đặt hai phương thức CanExecute và Executed như
sau:

Kết quả khi chạy chương trình và chọn vào một đối tượng để thực hiện xóa

Kết quả sau khi nhấn phím “Delete” trên bàn phím

12.2.3. Lệnh tự tạo


Tự tạo các lệnh của riêng trong nhiều trường hợp là cần thiết. Việc này
cũng không quá phức tạp trong WPF. Để làm được điều này, lớp lệnh tự tạo
phải hiện thực hoá giao diện ICommand. Tuy nhiên, ta có thể dùng lớp
RoutedUICommand là lớp có sẵn trong framework đã hiện thực hoá tốt giao
diện ICommand. Ví dụ, sau đây là cách tạo nên một lệnh cho phép chèn thêm
một khách hàng.

Trong file code-behind C#, ta tạo một lớp mới có tên là MyCommands
chứa một biến public kiểu RoutedUICommand. Lớp này được đặt trong cùng
namespace với đối tượng Window chính. Đoạn mã ví dụ như sau:

120
Để sử dụng RouteUICommand cần thêm
thư viện …Input

Câu hỏi ôn tập và bài tập


1. Để xử lý một sự kiện cần thực hiện những công việc gì?
A. Viết mã lệnh thực hiện các hành động phản ứng với sự kiện
B. Kết nối sự kiện với hàm xử lý sự kiện
C. Cả hai công việc trên
2. Một sự kiện định tuyến có thể là:
A. Sự kiện truyền xuống
B. Sự kiện truyền lên
C. Sự kiện trực tiếp
D. Một trong ba phương án a, b, c, tuỳ thuộc vào chiến lược dẫn tuyến của sự
kiện đó

121
E. Có thể đồng thời hai trong 3 phương án a, b, c
3. Một sự kiện định tuyến có thể lan truyền:
A. Từ phần tử nguồn tới phần tử bất kỳ trên cây trực quan
B. Lan truyền theo một trong hai hướng: từ phần từ nguồn đến nút gốc hoặc từ
phần tử nguồn đến các nút con của nó.
C. Chỉ lan truyền (ngược hay xuôi) qua các phần từ nằm trong đoạn từ
nút gốc tới phần tử nguồn mà có quan hệ họ hàng với phần tử nguồn.
4. Với mô hình sự kiện có định tuyến, một sự kiện lan truyền xuống được:
A. Lan truyền từ phần tử nguồn lên phần tử gốc trong cây trực quan
B. Lan truyền từ nút gốc đến phần tử nguồn trong cây trực quan
C. Lan truyền từ phần tử nguồn xuống các nút con trong cây trực quan
5. Khi gắn kết một lệnh với một đối tượng chịu tác động của lệnh, việc thực
hiện lệnh sẽ do:
A. Bản thân lệnh đó tự thực thi hành động tương ứng với ngữ nghĩa của
nó, người lập trình không phải tác động thêm gì.
B. Việc gắn kết chỉ có tác dụng thiết lập việc phát thông báo cho đối
tượng chịu tác động lệnh biết nó được ra lệnh gì mỗi khi lệnh được gọi, còn
người
lập trình phải viết mã lệnh thực thi lệnh đó như thế nào.

C. Nguồn phát lệnh xác định việc thực thi hành động
6. Ưu điểm của việc sử dụng lệnh có định tuyến so với xử lý sự kiện có định
tuyến:
A. Nguồn lệnh (nơi phát động lệnh) không bó chặt với đích lệnh (nơi xử
lý lệnh) – chúng không cần các tham chiếu trực tiếp lẫn nhau như trong trường
hợp liên kết bằng đơn vị xử lý sự kiện.
B. Lệnh có định tuyến sẽ tự động cho phép hoặc vô hiệu hoá tất cả các
điều khiển UI tương ứng khi đích lệnh xác định rằng lệnh đó bị vô hiệu hoá
C. Lệnh có định tuyến cho phép ta liên kết phím nóng và các dạng nhập
liệu khác như cơ chế phát động lệnh

122
D. Cả ba ưu điểm trên.
7. Trong mô hình lệnh có định tuyến, một khi một đơn vị xử lý lệnh đã được
kích hoạt thực hiện:
A. Giống như sự kiện có định tuyến, lệnh lại được lan truyền tiếp, do
vậy, có thể có nhiều đơn vị xử lý lệnh khác sẽ được thực hiện
B. Không đơn vị xử lý nào khác được gọi
C. Còn tuỳ lệnh đó có được đánh dấu “đã xử lý” hay chưa

123
BÀI 13: SỬ DỤNG STYLE
Mã bài: 24.13
Giới thiệu:
Thông thường, khi xây dựng một giao diện đồ hoạ, ta thường thiết lập
cùng giá trị các thuộc tính hiển thị trên nhiều đối tượng UI khác nhau. Ví dụ,
muốn đặt tất cả các tiêu đề (Label) trong ứng dụng với phông chữ “Times New
Roman”, cỡ 14px, in đậm. Điều này có thể thực hiện dễ dàng với CSS trong
một ứng dụng Web, nhưng không đơn giản đối với WinForm. WPF nhận ra sự
cần thiết này và giải quyết bằng việc đưa ra thành phần “Style”.
Mục tiêu:
- Biết công dụng của style
- Trình bày quy trình tạo tập tin style resource dictionary
- Biết cách sử dụng tập tin style resource dictionary
- Thiết kế giao diện sử dụng style resource dictionary
- Đảm bảo an toàn cho người và thiết bị.
Nội dung chính:

13.1. Các thành phần thuộc tính trong Style


Thành phần “Style” cho phép người lập trình lưu trữ một danh sách các
giá trị thuộc tính vào một nơi thuận tiện. Nó tương tự như cách làm việc của
CSS trong các ứng dụng Web. Thông thường, các Style được lưu trữ trong phần
Resource hoặc một thư mục Resource riêng của project. Các thuộc tính quan
trọng nhất của thành phần Style bao gồm BasedOn, TargetType, Setters và
Triggers.
Được xem như một loại tài nguyên, Style có thể được định nghĩa ở bất kỳ
phân cấp nào trong cây trực quan, ví dụ cho một StackPanel, Window hoặc
thậm chí ở mức Application. Việc đặt khai báo Style lẫn với các mã chức năng
XAML thường dễ gây nhầm lẫn khi mở rộng ứng dụng. Lời khuyên ở đây là
không đặt khai báo Style trong App.xaml hay các file chức năng xaml, mà lưu
chúng trong một file xaml tài nguyên riêng. Lưu ý rằng các tài nguyên có thể

124
được chia nhỏ thành các file độc lập sao cho các file ảnh như jpeg có thể được
lưu trữ riêng rẽ.
Một khi đã chia thành các file tài nguyên riêng thì vấn đề tiếp theo sẽ là
việc làm sao để tìm tham chiếu tới tài nguyên cần. Ở đây, ta dùng một giá trị
khoá duy nhất: Khi định nghĩa một tài nguyên trong XAML, định nghĩa một giá
trị khoá duy nhất cho tài nguyên đó thông qua thuộc tính x:Key. Kể từ sau đó,
có thể tham chiếu tới tài nguyên này bằng việc sử dụng giá trị này.
Sau đây, các thuộc tính quan trọng trong Style sẽ được lần lượt giới
thiệu.
13.1.1. BasedOn
Thuộc tính này giống như tính chất kế thừa, trong đó, một Style kế thừa
thuộc tính chung của một Style khác. Mỗi kiểu hiện thị chỉ hỗ trợ một giá trị
BaseOn. Sau đây là một ví dụ nhỏ:

13.1.2. TartgetType
Thuộc tính TargetType được sử dụng để giới hạn loại điều khiển nào được
sử dụng Style đó. Ví dụ nếu ta có một Style với thuộc tính TargetType thiết lập
cho nút bấm (Button), thì Style này sẽ không thể áp dụng cho kiểu điều khiển
TextBox. Cách thiết lập thuộc tính này minh họa trong ví dụ sau:

13.1.3. Setter

125
Setters cho phép thiết lập một sự kiện hay một thuộc tính với một giá trị
nào đó. Trong trường hợp thiết lập một sự kiện, chúng liên kết với một sự kiện
và kích hoạt hàm xử lý tương ứng. Trong trường hợp thiết lập một thuộc tính,
chúng đặt giá trị cho thuộc tính đó.
Sau đây là một ví dụ về việc sử dụng EventSetters để liên kết sự kiện,
trong đó, sự kiện nhắm chuột vào nút bấm (Click) được liên kết:

Tuy nhiên, Setter thường được dùng để thiết lập giá trị thuộc tính hơn cả. Ví dụ:

13.1.4. Trigger
Mô hình thiết lập kiểu hiển thị và khuôn mẫu của WPF cho phép định ra
các Trigger bên trong Style. Trigger là đối tượng cho phép áp dụng những thay
đổi về thuộc tính giao diện khi những điều kiện nhất định (ví dụ khi một giá trị
Property nào đó bằng true, hoặc một sự kiện nào đó xảy ra) được thoả mãn.
Ví dụ sau đây minh hoạ một Style có định danh được áp dụng cho điều
khiển Button. Style này định nghĩa một thành phần Trigger, có tác dụng thay
đổi thuộc tính màu chữ của nút bấm khi thuộc tính IsPressed (nút đang bị bấm
xuống) là true.

Một số dạng khác của Trigger sử dụng trong Style:

126
DataTrigger

DataTrigger Đại diện cho một Trigger áp dụng cho giá trị thuộc tính hoặc
thực hiện hành động khi dữ liệu liên kết thoả mãn một điều kiện định trước.
Trong ví dụ sau, DataTrigger được xác định sao cho nếu
như giá trị Tỉnh trong mục dữ liệu Nơi làm việc bằng “HN” thì màu chữ
của mục dữ liệu tương ứng trong

ListBox được tô đỏ:

Có một loại Trigger đặc biệt sử dụng nhiều hơn một giá trị để kích hoạt
hoạt động, có tên gọi là

Multitrigger. Với loại Trigger này ta có thể thiết lập nhiều điều kiện trong
một Trigger. Ví dụ:

127
Trong ví dụ này, đối tượng dữ liệu buộc với điều khiển phải có
TenCongViec=”CNTT” và Tinh=”HN”, thì màu chữ của mục dữ liệu tương
ứng trên ListBox được tô đỏ.
13.1.5.EventTrigger
EventTrigger là loại Trigger đặc biệt áp dụng cho một tập các hành động
tương ứng với một sự kiện. Các EventTrigger đặc biệt ở chỗ chúng chỉ cho
phép các hành động hoạt họa được kích hoạt. Chúng không cho phép các thuộc
tính bình thường được thiết lập làm cơ sở như đối với các Trigger khác. Sau
đây là một ví dụ của EventTrigger:

128
Một ví dụ đầy đủ về Style
Sau đây là một ví dụ đầy đủ về việc sử dụng Style. Trong ví dụ minh hoạ
này, hai Style được định nghĩa cho Panel chính. Style thứ nhất quy định các
thuộc tính tĩnh về phông chữ, áp dụng đối với đối tượng UI là Control. Style
thứ hai kế thừa các thuộc tính này từ Style thứ nhất và chỉ áp dụng cho Label.
Style thứ hai quy định thêm phản ứng của các đối tượng là Label trong
StackPanel khi con trỏ chuột lướt qua, cụ thể, màu chữ sẽ chuyển đỏ. Sau đây là
mã XAML tương ứng:
<Window x:Class="Bai4.Style"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Bai4"
mc:Ignorable="d"
Title="Style" Height="450" Width="800">
<Grid>
<StackPanel>
<!--Khai báo tài nguyên trong StackPanel-->
<StackPanel.Resources>
<!--Trong trường hợp này, tài nguyên là hai Style:-->
<!--(1) Style quy định về kiểu phông chữ, áp dụng với Control-->
<Style x:Key="baseStyle" TargetType="{x:Type Control}">
<Setter Property="FontFamily" Value="Times New Roman" />
<Setter Property="FontSize" Value="12" />
<Setter Property="FontStyle" Value="Italic" />
<Setter Property="HorizontalAlignment" Value="Center" />
</Style>
<!--(2) Style kế thừa từ Style trước, quy định phản ứng với sự kiện
-->
<Style BasedOn="{StaticResource baseStyle}" TargetType="{x:Type
Label}">
<!--Khai báo trigger-->
<Style.Triggers>
<!--Sự kiện khi con trỏ chuột lướt qua-->
<Trigger Property="IsMouseOver" Value="True">
<Setter Property="Foreground" Value="Red" />
</Trigger>
</Style.Triggers>
</Style>
</StackPanel.Resources>
<!--Kết thúc khai báo tài nguyên-->
<!--Khai báo phần tử trên giao diện-->
<Label>Lũ chúng ta ngủ trong giường chiếu hẹp,</Label>
<Label>Giấc mơ con đè nát cuộc đời con,</Label>
<Label>Hạnh phúc đựng trong một tà áo đẹp,</Label>
<Label>Một mái nhà yên rủ bóng xuống tâm hồn</Label>
<TextBlock>-Chế Lan Viên-</TextBlock>
</StackPanel>
</Grid>
</Window>

129
13.2. Tạo tập tin Style Resource Dictionary
Resource Dictionary là một cách lưu trữ các resource theo dạng hash
table. Mỗi phần tử trong resource là một đối tượng và có thể được truy xuất
thông qua định danh của chúng bằng cách dùng chỉ thị x:key. Đây là một giải
pháp để tách riêng các resource như template, style,… ra khỏi tài liệu XAML.
Resource Dictionary là một item template trong Visual Studio, vì vậy chỉ
cần Add > New Item trong Visual Studio để tạo một tài liệu .xaml mới với phần
tử gốc là <ResourceDictionary>.

13.3. Sử dụng tập tin Style Resource Dictionary


Trong tập tin Dictionary1.xaml, tạo một Control Template cho Button
vào trong ResourceDictionary:
<<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>
    <ControlTemplate x:Key="buttonTemplate" TargetType="{x:Type Button}">
            <Ellipse Stroke="Red" Fill="Azure"/>
    </ControlTemplate>
</ResourceDictionary>
Để sử dụng được ResourceDictionary này trong một tập tin XAML cụ
thể, cần tạo một ResourceDictionary mới và nhập nội dung của nó với tập tin
Dictionary1.xaml bằng cách thêm vào collection
ResourceDictionary.MergedDictionaries.
Với cách này, có thể thấy cách khác để tạo ResourceDictionary là gán giá
trị cho property Source đến tập tin xaml chứa một ResourceDictionary nguồn
cần lấy dữ liệu:
<Window x:Class="ResourceDictionaryDemo.Window1"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="ResourceDictionaryDemo" Height="300" Width="300"
>

130
    <Window.Resources>
        <ResourceDictionary>
            <ResourceDictionary.MergedDictionaries>
                <ResourceDictionary
                    Source="Dictionary1.xaml">
                </ResourceDictionary>
            </ResourceDictionary.MergedDictionaries>
        </ResourceDictionary>
    </Window.Resources>
    <Grid>
        <Button Template="{StaticResource buttonTemplate}">Hello</Button>
    </Grid>
</Window>
Ngoài ra có thể nạp ResourceDictionary trong code-behind:
ResourceDictionary resources = new ResourceDictionary();
resources.Source = new Uri("Dictionary1.xaml",UriKind.RelativeOrAbsolute);
 
button1.Template=(ControlTemplate)resources["buttonTemplate"];
Sử dụng ResourceDictionary, có thể tạo được các ứng dụng đa ngôn ngữ
(Multi Language) bằng cách kết hợp với Data Binding. Ngoài ra việc áp dụng
Theme cho ứng dụng cũng đòi hỏi cần phải sử dụng ResourceDictionary để chỉ
tới  tập tin xaml từ các assembly khác.

Câu hỏi ôn tập và bài tập


Viết chương cho phép người dùng lựa chọn các món ăn để làm thành thực đơn
các món ăn trong ngày mà cửa hàng thức ăn có bán. Giao diện gồm các điều
khiển:
ListBox, Label, Button như sau:

131
Hình 13.5. Form Danh sách thực đơn, Thực đơn hằng ngày
ListBox1: Hiển thị danh sách tất cả các món ăn
- Button “>”: chuyển một món được chọn từ ListBox1 qua ListBox2
- Button “>>”: chuyển tất cả các món từ ListBox1 qua ListBox2
- Button “<”: xóa món ăn được chọn trong ListBox2
- Button “<<”: xóa tất cả món ăn trong ListBox2
- Button “In thực đơn” sẽ hiển thị hộp thoại MessageBox với nội dung là các
món ăn đã chọn hiển thị trong ListBox2
- Button “Thoát” : đóng chương trình

132
BÀI 14: SỬ DỤNG TEMPLATE
Mã bài: 24.14
Giới thiệu:
Bằng việc sử dụng Style, ta có thể tạo ra một diện mạo nhất quán và dễ
sửa đổi cho giao diện ứng dụng. Tuy nhiên, đôi khi cần thiết kế nâng cao hơn
chẳng hạn, muốn các nút bấm không phải là hình chữ nhật như thường lệ mà là
hình ellipse. bạn muốn hiển thị một tập dữ liệu nhân viên trong một công ty,
trong đó, mỗi bản ghi nhân viên lại được trình bày theo một định dạng xác định.
Không thể đạt được điều này bằng những Setter căn bản trong Style. Trong
trường hợp đó, phải dùng đến khái niệm gọi là Khuôn mẫu (Template).
Trong WPF, có hai dạng khuôn mẫu được sử dụng: ControlTemplate
dùng để định lại cấu trúc hiển thị cho điều khiển UI; và DataTemplate dùng để
định ra cách thức hiển thị dữ liệu. Phần sau đây sẽ trình bày lần lượt hai dạng
khuôn mẫu này.
Mục tiêu:
- Biết công dụng của Control Template và Data Template
- Trình bày quy trình tạo và sử dụng template
- Thiết kế giao diện hiển thị dữ liệu sử dụng template
- Đảm bảo an toàn cho người và thiết bị
Nội dung chính:
14.1. Control Template
14.1.1. Khái niệm
Phần lớn các điều khiển đều bao gồm diện mạo và hành vi. Xét một nút
bấm: diện mạo của nó là vùng nổi lên mà ta có thể bấm vào, trong khi hành vi
là sự kiện Click được phát động để phản ứng với hành động nhắp chuột vào nút
bấm đó.
Đôi khi có những điều khiển cung cấp các hành vi mà ta cần nhưng lại
không có diện mạo mà ta mong muốn. Tới giờ, chúng ta có thể dùng các Setter
của thành phần Style để thiết lập các giá trị thuộc tính có ảnh hưởng tới diện
mạo của điều khiển. Tuy nhiên, để thay đổi cấu trúc của một điều khiển hoặc

133
thiết lập giá trị thuộc tính cho các component có chứa một điều khiển, ta cần
dùng đến ControlTemplate.
Trong WPF, ControlTemplate của một điều khiển định nghĩa diện mạo
cho điều khiển đó. Bạn có thay đổi cấu trúc hay diện mạo của một điều khiển
bằng cách định nghĩa một ControlTemplate mới cho dạng điều khiển đó. Trong
trường hợp bạn không định nghĩa riêng một ControlTemplate cho điều khiển
của bạn, thì một template ngầm định phù hợp với giao diện chung của hệ thống
sẽ được sử dụng, giống như những gì ta nhìn thấy đối với một nút bấm truyền
thống.
Một điều cần nhớ là khi bạn tạo một ControlTemplate cho điều khiển,
bạn đang thay thế toàn bộ ControlTemplate của điều khiển đó. Ví dụ, bạn có thể
định nghĩa ControlTemplate cho điều khiển Button như sau:
Định nghĩa cho Style của điều khiển Button như sau:

Phần tạo lưới trong Form và gọi Button sử dụng Style và không sử dụng
Style

134
Kết quả hiển thị:

14.1.2. Ví dụ
Trong phần này, chúng ta cùng xây dựng một ControlTemplate định
nghĩa một ListBox mà trong đó, các chỉ mục được sắp xếp theo chiều ngang
(thay vì chiều dọc như thông thường) và có các góc được uốn cong. Sau đây là
đoạn mã XAML minh hoạ:

135
Theo cách trên, bạn xây dựng một ControlTemplate thông qua sử dụng
một Style, cụ thể là khai báo trong một Setter cho thuộc tính Template. Một
cách khác nữa là bạn có thể gán trực tiếp thuộc tính Template của một điều
khiển cho một ControlTemplate. Với cách này, ControlTemplate cần dùng phải
được xây dựng trước, trong phần Resourse chẳng hạn, và được gán khoá định
danh thông qua x:Key, và sau đó được sử dụng như một tài nguyên tĩnh (khai
báo StaticResource).

Như bạn có thể thấy trong ví dụ trên, lớp ControlTemplate cũng có thuộc
tính TargetType như đối với lớp Style. Tuy nhiên, cần lưu ý rằng, nếu ta xây
dựng một ControlTemplate độc lập, với thuộc tính TargetType được thiết lập
cho một kiểu điều khiển nào đó, thì ControlTemplate đó không được tự động áp
dụng cho kiểu điều khiển này. Cũng lưu ý rằng thuộc tính TargetType là bắt
buộc trong một khai báo ControlTemplate nếu như template đó có chứa thành
phần ContentPresenter.

136
Trong ví dụ trên, một thuộc tính quan trọng cần có là IsItemsHost. Thuộc
tính IsItemsHost được sử dụng để xác định đây là template của một điều khiển
chứa các mục con, và các mục con sẽ được sắp xếp trong đó. Thiết lập thuộc
tính này bằng true trong StackPanel có nghĩa là bất kỳ một mục nào được thêm
vào ListBox sẽ được xếp vào StackPanel. Chú ý thuộc tính này chỉ có trong
kiểu Panel.
Kết quả chương trình:

14.2. Data Template


1.1. Khái niệm
DataTemplate được sử dụng để định ra cách thức hiển thị các đối tượng
dữ liệu. Đối tượng DataTemplate đặc biệt hữu dụng khi bạn móc nối một điều
khiển chứa mục con (ItemsControl) kiểu như ListBox với một danh mục dữ
liệu. Không có sự định hướng cụ thể, một ListBox sẽ ngầm định hiển thị các
đối tượng trong danh sách dưới dạng chuỗi ký tự. Với việc sử dụng
DataTemplate, chúng ta có thể định khuôn dạng hiển thị của mỗi mục con trong
ListBox với nhiều đặc tính trực quan như màu sắc, hình ảnh, phông chữ…

1.2. Ví dụ
Trong ví dụ này, thông tin về các nhân viên trong một văn phòng được
hiển thị sử dụng DataTemplate. Trước hết, ta phải định nghĩa nguồn dữ liệu, cụ
thể ở đây là danh sách nhân viên.

Để làm điều này, đầu tiên, ta xây dựng lớp nhân viên (Person), đơn giản
bao gồm họ tên (Name) và ảnh chân dung (ImageRef). Sau đây là mã C#:

137
Tiếp theo, ta xây dựng lớp chứa danh sách nhân viên, giả sử có tên Staffs. Mã
lệnh C# như sau:

Câu hỏi ôn tập và bài tập


Viết chương trình minh họa việc hiển thị lịch, thiết kế giao diện form như
sau. Yêu cầu: khi nhấp nút hiển thị thì các ngày được chọn sẽ hiển thị trên
MessageBox

Hình 14.3. Form hiển thị ngày/tháng/năm


Gợi ý lập trình cho nút Hiển thị

138
139
BÀI 15: TRUY XUẤT CƠ SỞ DỮ LIỆU
Mã bài: 24.15
Giới thiệu:
Điều khiển giúp hiển thị dữ liệu dưới dạng cây thư mục có thể thu hẹp và
mở rộng các đối tượng trong đó được Visual Studio phát triển là ListView và
TreeView.
Mục tiêu:
- Trình bày quy trình tạo ADO.NET Entity Data Model
- Trình bày các lớp đối tượng bên trong Entity Data Model
- Biết quy trình đọc, thêm, xóa, sửa dữ liệu theo Entity Data Model
- Hiển thị danh sách dữ liệu trên Window
- Thêm, xóa, sửa dữ liệu
- Đảm bảo an toàn cho người và thiết bị
Nội dung chính:

15.1. Tạo ADO.NET Entyty Data Model


Tạo cơ sở dữ liệu trong SQL Server với CSDL tên QLTHUVIEN như sau:

140
go
if exists(select name from sysdatabases where name='QLTHUVIEN')
drop Database QLTHUVIEN
/* Tạo cơ sở dữ liệu*/
go
Create Database QLTHUVIEN
go
use QLTHUVIEN
go
/*=============DANH MUC HỆ ĐÀO TẠO ==============*/
Create table HEDAOTAO
(
MAHE char(5)primary key,
TENHE nvarchar(100) not null,
)
/*==============DANH MUC SINHVIEN ============*/
Create table SINHVIEN
(
MASV char(10) primary key,
TENSV nvarchar(200)not null,
NGAYSINH date,
GIOITINH nvarchar(5),
MAHE CHAR (5) references HEDAOTAO (MAHE)
)
/*==============NHAP DU LIEU LOAIPHONG=============*/
INSERT INTO HEDAOTAO(MAHE,TENHE)
values('CD',N'Cao đẳng')
INSERT INTO HEDAOTAO(MAHE,TENHE)
values('TC',N'Trung cấp')
INSERT INTO HEDAOTAO(MAHE,TENHE)

141
values('SC',N'Sơ cấp')
/*==============NHAP DU LIEU PHONG=============*/
INSERT INTO SINHVIEN(MASV,TENSV,NGAYSINH,GIOITINH,MAHE)
values('SV01',N'Nguyễn Văn An', '01/02/2004', 'Nam', 'CD')
INSERT INTO SINHVIEN(MASV,TENSV,NGAYSINH,GIOITINH,MAHE)
values('SV02',N'Trần Đình Bốn', '04/05/2003', 'Nam', 'CD')
INSERT INTO SINHVIEN(MASV,TENSV,NGAYSINH,GIOITINH,MAHE)
values('SV03',N'Lương Xuân Trường', '11/02/2002', 'Nam', 'TC')
INSERT INTO SINHVIEN(MASV,TENSV,NGAYSINH,GIOITINH,MAHE)
values('SV04',N'Nguyễn Thị Ngọc Anh', '09/08/2002', N'Nữ', 'CD')
INSERT INTO SINHVIEN(MASV,TENSV,NGAYSINH,GIOITINH,MAHE)
values('SV05',N'Trịnh Thị Mến', '09/13/2004', N'Nữ', 'TC')
INSERT INTO SINHVIEN(MASV,TENSV,NGAYSINH,GIOITINH,MAHE)
values('SV06',N'Trương Tiến Đạt', '02/04/2004', 'Nam', 'TC')
Để cài đặt được Entity NetFrameWork cần tiến hành như sau:
Bước 1: Tạo Project.
Bước 2: Chọn menu Project > Manage NuGet Packages xuất hiện cửa sổ như
sau:

Hình 15.1. Màn hình để lựa chọn cài đặt Entity NetFrameWork
Bước 3: Trong NuGet Package Manager, nhấp chọn liên kết Browse.

142
Hình 15.2. Màn hình để cài đặt Entity NetFrameWork
Bước 4: Nhập vào chữ entity để tìm kiếm và lựa chọn sau đó nhấn vào Install.
Sau khi cài đặt xong tiến hành tạo Model như sau: Solution Explorer and
choose Add > New Item. In the left pane, under the C# node, choose Data and
in the middle pane, choose ADO.NET Entity Data Model.

Hình 15.3. Thêm Model

143
Hình 15.4. Màn hình chọn kết nối CSDL

Hình 15.5. Màn hình lựa chọn kết nối sẵn có

144
Hình 15.6. Lựa chọn tên Server và CSDL

Hình 15.7. Lựa chọn các đối tượng làm việc

145
Hình 15.8. Hoàn thành việc tạo Model bằng Entity NetFrameWork

15.2. Giới thiệu các lớp đối tượng


Tạo lớp đối tượng Data Access Object để kết nối đến CSDL QLTHUVIEN

146
Tạo lớp đối tượng BUS (Business) để thao tác với các bảng dữ liệu

15.3. Hiển thị dữ liệu trên ListBox/ComboBox


Viết hàm để đưa dữ liệu lên bảng từ câu lệnh truy vấn SQL với tham số truyền
vào là “string sql”

Gọi hàm load dữ liệu và đưa dữ liệu lên Combo:

147
15.4. Hiển thị dữ liệu trên DataGrid
Đoạn code để hiển thị dữ liệu lên DataGrid

Đoạn code khi nhấp chọn vào DataGrid dữ liệu được hiển thị lên từng điều
khiển trên Form

15.5. Thêm, xóa, cập nhật dữ liệu


Nút thêm thông tin sinh viên

148
Nút sửa thông tin sinh viên

Nút xóa thông tin sinh viên

Câu hỏi ôn tập và bài tập


1. Thiết kế Form có giao diện như mẫu sau:

149
Hình 15.8. Form sử dụng ListView
Yêu cầu:
Dùng ListView và các hình ảnh phù hợp để thiết kế Form
2. Thiết kế Form có giao diện như mẫu sau:

Hình 15.9. Form sử dụng ListView có CheckBox


Yêu cầu:
Dùng ListView có Checkbox và các hình ảnh phù hợp để thiết kế Form

150
3. Thiết kế Form có giao diện như mẫu sau:

Hình 15.10. Form sử dụng ListView kết hợp TreeView


Yêu cầu:
- Dùng ListView, TreeView và các hình ảnh phù hợp để thiết kế Form
- Phương thức thanh toán gồm: Trả góp, Khoán gọn và Bảo hiểm.
- Người dùng nhấn chọn xe cần mua trên ListView, hai điều khiển
NumericUpdown là Số lượng: và Thông tin mua hàng: được kích hoạt cho
người dùng nhập số lượng và thông tin mua hàng.
- Khi đã đặt hàng xong, người dùng nhấn vào button Lưu để lưu lại thông tin
mua hàng. Thông tin mua hàng được hiển thị trên MessageBox.

Hình 15.11. Hộp thoại thông báo thông tin mua hàng

151
TÀI LIỆU THAM KHẢO

[1]. Trang: https://wpf-tutorial.com/vi


[2]. Trang: https://stackoverrun.com/vi
[3]. Trang: https://www.w3schools.com/cs/
[4]. Trang: https://techtalk.vn/
[5]. Windows Presentation Foundation, URL:
http://msdn.microsoft.com/enus/library/ms754130.aspx.
[6]. Nguyễn Hoàng Hà – Nguyễn Văn Trung, Giáo trình C# và ứng dụng, Khoa
Công nghệ thông tin, Đại học Huế
[7]. Dương Quang Thiện, C# và NET Framework – Lập trình Visual C# thế
nào?, Nhà xuất bản tổng hợp TPHCM.
[8]. Nguyễn Ngọc Bình Phương – Thái Thanh Phong, Các giải pháp lập trình
C#, NXB Giao thông vận tải.
[9]. Phạm Phương Hoa – Vũ Trọng Luật – Phạm Quang Hiển, Lập trình với
C# xây dựng ứng dụng, NXB Thanh niên.

152

You might also like