Thu thập thông tin khách hàng như thế nào và khi nào?

Mr[K]id | 09:05 | 0 nhận xét
CRM là hệ thống quản lý dịch vụ khách hàng, đây là một hệ thống rất mạnh mẽ, nhưng hệ thống CRM chỉ có thể hoạt động nếu doanh nghiệp thu thập được những thông tin dữ liệu khách hàng đầy đủ và hợp lý. Thông tin khách hàng có thể lấy từ rất nhiều nguồn: từ báo cáo chính phủ, từ các hiệp hội thương mại v.v.. Nhưng vào những thời điểm khác nhau, doanh nghiệp cần những thông tin khách hàng thích hợp khác nhau.

1. Trước khi bạn có khách hàng

Sử dụng các thông tin về nhân khẩu học - demographic (đặc điểm dân cư: ngày sinh, giới tính, thu nhập, chủng tộc v.v.. trong một cộng động trong một khoảng thời gian), về psychographic (tính cách, sở thích, lối sống v.v..) để xác định bạn sẽ tiếp thị những loại hàng hoá và dịch vụ gì, và tiếp thị như thế nào?

Tips: Xác định ra 3 nhóm khách hàng chủ yếu và tập trung điều tra xem họ thích & không thích những gì? 3 nhóm khách hàng đó có thể là:

- Nhóm khách hàng chi nhiều tiền nhất
- Nhóm khách hàng lâu dài
- Nhóm những khách hàng bỏ sang giao dịch với những doanh nghiệp cạnh tranh với bạn

2. Tiếp cận với một khách hàng hay một khách hàng tiềm năng

Người ta không cứ phải mua hàng hoá dịch vụ của bạn mới trở thành đối tượng khách hàng bạn cần thu thập thông tin. Bạn vẫn có thể điều tra họ về:

- Họ biết đến doanh nghiệp của bạn từ đâu?
- Ấn tượng đầu tiên của họ về doanh nghiệp của bạn?
- Họ phải tốn bao nhiêu công sức để liên hệ với bạn? (Nếu bạn là nhà bán lẻ, họ phải lái xe bao xa đến chỗ bạn; Nếu họ là doanh nghiệp, họ liên lạc với bạn qua công cụ tìm kiếm trên internet, hay qua quảng cáo trên báo đài v.v..)
- Họ có thể kiếm những hàng hoá dịch vụ thay thế (cho hàng hoá dịch vụ của bạn) ở đâu?
- Họ thích gì ở những doanh nghiệp cạnh tranh với bạn?

3. Khi mới thiết lập quan hệ với khách hàng

Sau lần giao dịch đầu tiên, bạn có thể bắt đầu phát triển cơ sở dữ liệu về khách hàng đó:
- Lần giao dịch đầu tiên diễn ra khi nào?
- Họ trả bao nhiêu cho lần giao dịch đó?
- Họ có yêu cầu cụ thể nào khác không?
- Quy mô của lần giao dịch đó?
- Giao dịch cái gì?
- Họ có phàn nàn vấn đề gì không?
- Họ liên hệ với bạn như thế nào, bằng cách nào?

4. Khi đã làm ăn với khách hàng đủ lâu

Tuy với mỗi doanh nghiệp có nhiều đặc điểm khác nhau, nhưng hầu như bất kì doanh nhân nào cũng biết được đâu là khách hàng tốt của mình. Nếu là nhà bán lẻ, bạn biết được đâu là người thường xuyên đến mua hàng, nếu bạn là nhân viên bán hàng công nghiệp, bạn biết ai là người mua nhiều nhất và ít phàn nàn nhất. Phân loại những khách hàng đó để thực hiện những cuộc điều tra riêng biệt & cụ thể với từng loại, nhằm tìm ra:

- Xu hướng trong ngành kinh doanh của bạn?
- Doanh nghiệp có những vấn đề nào khiến bạn mất khách hàng vào tay những đối thủ cạnh tranh?
- Xu hướng về sản phẩm; phương thức bán hàng, vận chuyển; và những xu hướng trong các thành phần khác của quan hệ khách hàng.

5. Khi quan hệ với khách hàng đang rơi vào “khoảng lặng”

Rất nhiều doanh nghiệp nhận thấy có những lúc tự nhiên những khách hàng quen lại không giao dịch với mình nữa, đặc biệt là những doanh nghiệp có hồ sơ Dịch vụ / Mua bán - với khách hàng theo mô hình Đồng hồ cát (Hourglass Customer Service / Sales Profile – chúng ta sẽ tìm hiểu ở những bài sau).

Nếu bạn là nhà bán lẻ, bỗng nhiên bạn có thể thấy khách quen không đến mua hàng của mình nữa, có thể vì họ chuyển chỗ ở, chuyển chỗ làm việc v.v.. Nhưng không có nghĩa là trong tương lai họ không còn là khách hàng của bạn nữa. Trái lại, họ vẫn là những khách hàng quan trọng cả ở thì hiện tại lẫn tương lai. Hiện tại họ không mua hàng của bạn nữa, nhưng có thể theo lời giới thiệu của họ, hàng xóm, và trong tương lai là con, cháu họ v.v.. sẽ đến mua hàng của bạn. Vậy khi “khoảng lặng” tự nhiên trong quan hệ khách hàng xảy ra, hãy điều tra xem trong suốt quá trình giao dịch từ trước tới nay với bạn, họ thích gì và không thích gì, những thông tin này sẽ cho bạn nhiều lời khuyên bổ ích.

6. Giai đoạn cuối của mối quan hệ

Khi một khách hàng dừng việc làm ăn với bạn, họ trở thành nguồn thông tin vô cùng quan trọng mà bạn nhất thiết phải tìm hiểu:

- Có những rắc rối nào trong dịch vụ khách hàng?
- Phải chăng hàng hoá dịch vụ của bạn không còn đáp ứng được nhu cầu của họ nữa?
- Thay vì bạn, họ sẽ bắt đầu làm ăn với doanh nghiệp nào khác? So sánh giữa doanh nghiệp đó và bạn?
- Nguyên nhân khách hàng không làm ăn với bạn nữa bắt nguồn từ mối quan hệ giữa họ và bạn, hay là không? (ví dụ tình hình kinh doanh của họ có sự thay đổi, không cần những loại hàng hoá dịch vụ như của bạn nữa)

Với những kiến thức cơ bản này, bạn sẽ tìm thấy những tiêu thức thiết yếu nhất trong điều tra thu thập thông tin khách hàng, bạn vừa làm giảm chi phí điều tra, vừa tăng chất lượng thông tin khách hàng, qua đó nâng cao hiệu quả của hệ thống CRM.

Tổng quan về CRM

Mr[K]id | 08:41 | 0 nhận xét
Nếu bạn đã từng mua 1 sản phẩm tại bất kỳ trang thương mại điện tử nào, thì chắc hẳn bạn sẽ rất bất ngờ bởi thường xuyên nhận được thư chào hàng mỗi khi trang này giới thiệu sản phẩm mới, các chương trình ưu đãi hay họ sẽ gửi cho bạn một e-mail kèm theo lời chào mời khuyến mãi hấp dẫn khi bạn mua hàng trở lại. Thật ra, không có gì là ngạc nhiên cả. Ngày nay, tất cả công việc trên đều được thực hiện tự động nhờ hệ thống Quản trị mối quan hệ với khách hàng (Customer relationship management - CRM).

Xu hướng sử dụng CRM để tạo dựng và duy trì các mối liên hệ với khách hàng đang ngày càng trở nên phổ biến trong kinh doanh ngày nay. Việc hàng nghìn khách hàng cùng lúc nhận được những lá thư thăm hỏi cũng như những lời mời giảm giá hấp dẫn không còn là điều gì xa lạ nữa. Với CRM, bạn có thể dễ dàng trả lời câu hỏi: Liệu sản phẩm do công ty bạn sản xuất có đáp ứng tốt hơn nhu cầu của khách hàng được không?

Vậy Customer Relationship Management là gì?

Trong các hoạt động kinh doanh cũng như quản lý hành chính, mỗi công ty đều có những mối quan hệ với khách hàng, với các đối tác kinh doanh mà mình phải làm việc, phục vụ hoặc cộng tác. Những mối quan hệ này luôn diễn ra giữa hai đội ngũ- một bên là các nhân viên trong công ty và bên kia là các khách hàng, đối tác kinh doanh có quan hệ với công ty. Vì vậy, công ty cần có một hệ thống quản lý sao cho vừa tạo điều kiện cho các nhân viên thực thi tốt mối quan hệ với khách hàng, vừa giúp cho việc quản lý khách hàng được hiệu quả hơn. Và CRM đã ra đời từ đó khi cùng một lúc phục vụ được cả hai yêu cầu trên.

Viết tắt của cụm từ Quản trị mối quan hệ với khách hàng (Customer Relationship Management), thuật ngữ CRM xuất hiện từ đầu những năm 1990 tại các công ty tư vấn kinh doanh Mỹ. Mong muốn của các chuyên gia khi xây dựng CRM là nhằm tạo ra một phương pháp có thể phát hiện các đối tượng tiềm năng, biến họ thành khách hàng, và sau đó duy trì lâu dài các khách hàng này cho công ty. Đây là một phần mềm giúp các công ty phục vụ khách hàng tốt hơn. Hoạt động của CRM tạo nên một môi trường tựa như “văn phòng ảo” giúp cho việc quản lý được liên tục, không phụ thuộc vào việc nhân viên đang làm việc tại nhiệm sở hay đang đi công tác. Hạt nhân của CRM là một hệ thống cơ sở dữ liệu tổng hợp về khách hàng do các bộ phận khác nhau trong công ty thu thập. Hệ thống CRM có thể được thiết kế gồm nhiều thành phần như quản lý thông tin khách hàng, quản lý tương tác khách hàng, quản lý quy trình bán hàng, quản lý maketing, quản lý sản phẩm dịch vụ hay báo cáo thống kê.... Qua việc tối ưu hóa các chu trình và cung cấp cho nhân viên bán hàng mọi thông tin đầy đủ liên quan đến khách hàng, CRM cho phép các công ty thiết lập những mối quan hệ có lợi hơn với khách hàng trong khi cắt giảm được chi phí hoạt động.

Hiệu quả của hệ thống CRM còn thể hiện ở tính đơn giản khi khách hàng có thể trao đổi thông tin với công ty theo bất cứ cách nào mà khách hàng thích, vào bất cứ thời điểm nào, thông qua bất cứ kênh liên lạc nào, bằng bất cứ ngôn ngữ nào... Dù các yêu cầu của khách hàng có thể phải đi qua những kênh nội bộ phức tạp mới đến đúng bộ phận phụ trách về sản phẩm, dịch vụ đó, nhưng thông qua hệ thống CRM, khách hàng sẽ có cảm giác đang giao tiếp với một thực thể duy nhất và nhận được sự chăm sóc mang tính cá nhân.

Việc ứng dụng CRM sẽ tiết kiệm được rất nhiều chi phí cho các công ty. Thông thường, chi phí để tiếp cận một khách hàng mới cao gấp 5 đến 15 lần chi phí duy trì một khách hàng đã có sẵn. Chi phí bán hàng và chi phí phục vụ khách hàng cũ cũng thấp hơn nhiều so với một khách hàng mới. Những khách hàng trung thành thường xuyên mua hàng sẽ ít chú ý đến giá cả hơn và cũng dễ phục vụ hơn. Còn những khách hàng hài lòng với công ty sẽ khen ngợi công ty với nhiều người khác, qua đó giúp công ty có thêm những khách hàng mới.

Bài học và những thành công của các tập đoàn lớn trên thế giới như Gartner, Sap, Oracle, Siebel... khi ứng dụng CRM đã cho thấy: đây là một giải pháp hợp lý và tiết kiệm nhất cho công ty trong việc quản trị khách hàng. Cũng chính các “đại gia” này đã làm sôi động thị trường CRM năm 2004 với doanh thu đạt tới 11,9 tỷ USD và tốc độ tăng trưởng đạt gần 9%/ năm.

Các chức năng của một hệ thống CRM

Nhờ hệ thống CRM, nhân viên giao dịch sẽ dễ dàng nhận ra nhiều đối tượng khách hàng, phối hợp với các bộ phận kỹ thuật khác trong công ty thực hiện các hoạt động maketing, bán hàng và cung cấp dịch vụ phù hợp, nhằm tối ưu hoá lợi nhuận và mang lại sự thoả mãn cao nhất cho khách hàng. CRM còn giúp ban lãnh đạo công ty xem xét, đánh giá hiệu quả công việc của các nhân viên để đưa ra được các chính sách khen thưởng hoặc kỷ luật. Nhìn chung, CRM có các chức năng sau:

Chức năng Giao dịch: CRM hoạt động tương tự như đối với chương trình Outlook của Microsoft. Nó cho phép bạn giao dịch thư điện tử trong mạng lưới người sử dụng CRM, đồng thời giao dịch thư tín với bên ngoài nhờ khai báo các tài khoản POP3.

Chức năng Phân tích: CRM cho phép công ty tạo lập và phân tích thông tin để quản lý và theo dõi những việc cần làm, chẳng hạn công việc diễn ra với khách hàng nào, trong bao lâu, thuộc dự án hay đề tài nào, do ai chịu trách nhiệm…

Chức năng Lập kế hoạch: CRM giúp bạn bố trí lịch làm việc cho cá nhân, cho tập thể, gồm lịch hàng ngày, lịch hàng tuần và lịch hàng tháng.

Chức năng Khai báo và quản lý:
CRM cho phép khai báo và quản lý các mối quan hệ với khách hàng để nắm được đó là đối tượng nào trên cơ sở những thông tin hồ sơ đơn giản về họ. CRM sẽ giúp xác định có những khách hàng nào thường xuyên quan hệ với công ty, công ty có những cuộc hẹn làm việc với khách hàng nào, khách hàng là đối tác liên quan tới kế hoạch nào cần ưu tiên...

Chức năng Quản lý việc liên lạc: CRM cho phép quản lý và theo dõi các cuộc gọi điện thoại trong công ty, giúp bạn đặt được kế hoạch vào những thời gian nào cần gọi cho ai, gọi trong bao lâu và bạn đã thực hiện chưa hay đã quên mất…

Chức năng Lưu trữ và Cập nhập: CRM cho phép bạn đọc và ghi tài liệu dù là bất cứ dạng văn bản gì, nhờ đó, người sử dụng hệ thống CRM có thể chia sẻ với nhau về các tài liệu dùng chung, những tài liệu cần cho mọi người tham khảo. Đặc biệt khi nhân viên đi công tác xa, anh ta vẫn sử dụng được một cách dễ dàng kho tài liệu chung của công ty mình, đồng thời có thể gửi vào đó những hồ sơ tài liệu mới cho đồng nghiệp bất chấp khoảng cách địa lý… Có thể nói, CRM đã loại bỏ hoàn toàn việc gửi văn bản đính kèm qua thư điện tử đến với mọi người một cách rời rạc như trước đây.

Chức năng Hỗ trợ các dự án: CRM cho phép khai báo và quản lý thông tin cần thiết về những dự án mà công ty bạn cần lập kế hoạch và triển khai. Cùng với những thông tin chính về dự án, bạn có thể quản lý danh sách các thành viên tham gia dự án, họ thuộc các công ty nào, tiến trình công việc diễn ra như thế nào, thời điểm các cuộc hẹn ra sao, các hợp đồng nào cần ký kết…. Bạn cũng có thể phân chia dự án thành các dự án nhỏ hơn và lên lịch trình thực hiện chúng.

Chức năng Thảo luận: CRM tạo ra môi trường giao lưu thông tin công khai trên toàn hệ thống thông qua việc viết tin, trả lời tin… CRM có thể giúp từng nhóm người trao đổi trực tuyến để thể hiện quan điểm, ý kiến của mình về một vấn đề nào đó, bất kỳ họ đang ngồi tại cơ quan hay đang đi công tác.

Chức năng Quản lý hợp đồng:
CRM cho phép quản lý danh sách các hợp đồng kèm theo, dù đó là những nguyên bản hợp đồng lưu dưới dạng PDF.

Chức năng Quản trị:
CRM cho phép các nhà quản trị công ty xác lập vai trò và vị trí của những nhân viên bán hàng, nhân viên quan hệ khách hàng, qua đó quản lý và phát huy hết vai trò của họ.

Làm thế nào có chương trình CRM thực sự hiệu quả?

Theo ước tính của hãng Forrester Research thì trong năm nay, các công ty trên toàn thế giới sẽ chi khoảng 13 tỷ USD vào hệ thống CRM. Tuy nhiên, không ít các công ty đã phải thừa nhận rằng họ luôn gặp thất bại trong việc duy trì mối liên hệ với khách hàng. Còn theo hãng nghiên cứu và phân tích thị trường Gartner, có đến 70% các dự án CRM được triển khai không thành công, nhiều công ty đã vì thế mà chùn bước và xem CRM như một cuộc hành trình đáng sợ. Vậy đâu là lý do? Có phải các công ty chưa hiểu hết về CRM hay họ chưa thực sự quan tâm tới CRM?

Theo Tom Siebel, một trong những chuyên gia hàng đầu về CRM, thì có 7 nguyên nhân khiến các dự án CRM thất bại, đó là: Sự chưa hiểu biết về CRM của ban lãnh đạo công ty; Thiếu các kế hoạch chiến lược; Các dữ liệu không đầy đủ;: Thiếu chuyên môn; Thiếu những nỗ lực thúc đẩy mối quan hệ với khách hàng; Chu trình công nghệ không hợp lý; Các yếu tố văn hóa của công ty.

Mặc dù có nhiều nguyên nhân, nhưng theo Tom thì nếu tháo gỡ được các vướng mắc khi triển khai CRM, các công ty vẫn có thể đạt được thành công. “Để CRM thực sự đạt hiệu quả, bạn không chỉ đơn thuần mua phần mềm CRM và cài đặt là xong, mà bạn phải xác định loại thông tin gì về khách hàng cần phải có và sử dụng các thông tin đó như thế nào. Tiếp theo, bạn cần làm rõ tất cả các cách thức để thông tin về khách hàng đến được với công ty, dữ liệu này lưu trữ ở đâu, lưu trữ như thế nào và hiện đang được sử dụng ra sao?”- Tom nói.

Sự quan tâm sâu sắc từ các nhà quản lý cấp cao

CRM sẽ không thể thành công nếu không có sự quan tâm sâu sắc từ phía các nhà quản lý cấp cao. Những nhân vật này nên sẵn lòng tham gia và lãnh đạo hệ thống CRM với mong muốn đem lại những kết quả tốt nhất. Các công ty sẽ tránh khỏi nhiều khó khăn, vướng mắc trong quá trình triển khai CRM nếu các nhà quản lý cấp cao không phó mặc quyền quản lý và điều hành cho một bộ phận riêng biệt. CRM cần sự hỗ trợ từ tất cả mọi thành viên trong công ty, đặc biệt là ban lãnh đạo và bộ phận IT, thay vì để một nhóm các nhân viên tự mình điều hành và xử lý các vấn đề phát sinh. Trước tiên hãy xác định các quy trình làm việc và tác động của CRM, sau đó mới nghĩ đến các yếu tố kỹ thuật khi triển khai. Yếu tố con người khi áp dụng CRM là một trong những thách thức lớn nhất. Do vậy, yêu cầu đặt ra là các nhà quản lý cấp cao trong công ty cần tham gia từ đầu quá trình triển khai CRM và phải làm sao để hệ thống CRM được ứng dụng một cách hiệu quả nhất.

Cải thiện các quy trình và cách thức kinh doanh

Tom trích dẫn lời khuyên của Rob Bois, một nhà phân tích tại AMR Research: “Các công ty cần phải tiếp cận CRM theo một lập trường quan điểm kinh doanh duy nhất. Hãy nhận ra đâu là nơi mà các quy trình quản lý khách hàng bị đứt quãng hay cần chỉnh sửa, trước khi đánh giá tính hiệu quả của hệ thống CRM, cũng như tăng cường yếu tố kỹ thuật cho các phần mềm CRM”. Rất nhiều trường hợp, các vấn đề được giải quyết ổn thỏa bằng việc cải thiện các quy trình và cách thức kinh doanh, thay vì bỏ thêm tiền để nâng cấp phần mềm và hệ thống CRM. Cả Tom và Bois đều cho rằng: “Bạn đừng tự động hoá các quy trình và cách thức kinh doanh yếu kém”.

Trong quá trình cải thiện các quy trình và cách thức kinh doanh, công ty cần có biết tìm ra mô hình CRM phù hợp với các đặc thù kinh doanh của công ty mình, chứ không phải “gọt giũa” các hoạt động đó cho phù hợp với những phần mềm CRM. Việc triển khai CRM sẽ gặp rất nhiều khó khăn, nếu công ty bỏ qua khâu tổ chức biện pháp thực hiện sao cho hiệu quả nhất. Và các nhà quản lý nên dành nhiều thời gian của mình cho việc thu thập và sắp xếp dữ liệu, để biến dữ liệu thành một lợi thế, chứ không phải một chướng ngại vật.

Xây dựng một chu trình quản lý khách hàng

Sở dĩ Oracle triển khai thành công hệ thống CRM là nhờ trước, công ty này đã soạn thảo một chu trình quản lý khách hàng hiệu quả trên giấy tờ. Chu trình này đặt việc xác định, phân loại, lập mục tiêu và quan hệ tương tác với khách hàng trong một chuỗi các cơ sở thông tin liên tục, nhằm tạo ra những mối quan hệ sâu sắc hơn và tốt hơn với khách hàng. Chu trình cần phải thỏa mãn các yêu cầu “đúng”: đúng khách hàng, đúng sản phẩm, đúng lúc, đúng giá, đúng kênh phân phối, đúng thông điệp và đúng chi phí.

Tất nhiên, thỏa mãn các yêu cầu “đúng” đó không phải là việc dễ dàng. “Tại rất nhiều công ty, dữ liệu về khách hàng thường bị “chẻ nhỏ” và phân tán trong các hệ thống lưu trữ khác nhau, vì thế chúng có rất ít khả năng tạo ra một bức tranh toàn cảnh về khách hàng. Việc này không chỉ ảnh hưởng đến công tác tiếp thị, làm tăng chi phí dịch vụ, mà còn làm giảm hiệu quả của kênh quan hệ khách hàng. Giải pháp cho vấn đề này là đưa tất cả dữ liệu về khách hàng tập trung về một nơi theo mô hình dữ liệu thống nhất”- Tom nói.

Bên cạnh đó, việc phân loại khách hàng thường xuyên, hay việc tìm hiểu khách hàng nào mang lại lợi nhuận nhiều nhất, lợi nhuận trung bình và lợi nhuận ít nhất cũng rất cần thiết, bởi dựa vào đó, công ty có thể vạch ra một chiến lược để duy trì và phát triển các khách hàng, nhằm tăng thêm lợi nhuận cho công ty, đồng thời loại bỏ các khách hàng không mang lại lợi nhuận.

Sau cùng, nhận ra những vấn đề vướng mắc khi triển khai CRM trong quá khứ, nhiều công ty đang tỏ ra cẩn trọng hơn khi tiến hành các bước thực hiện CRM, nhằm đảm bảo cho các hoạt động kinh doanh ít rủi hơn, cũng như việc chăm sóc khách hàng ngày một tốt hơn. Các công ty đã quan tâm nhiều hơn đến những mục tiêu của mình, một vài công ty xem CRM như một giải pháp có tính chiến lược cho mình, trong khi số khác lại xem đây như là một quy trình trong các hoạt động của công ty.

Quả đúng như vậy, có rất nhiều công ty hiện nay đang phải đầu tư hàng triệu USD để “dọn dẹp” và tổ chức lại các khối dữ liệu khổng lồ, nhằm xây dựng một nền tảng dữ liệu hợp lý hỗ trợ hoạt động kinh doanh. Vậy thì tại sao bạn không tránh xa bài học đó bằng việc thiết lập một hệ thống CRM hiệu quả ngay từ bây giờ?

Green Talk 2010 - TTXVN

Mr[K]id | 15:33 | 0 nhận xét

Here Comes Goodbye - Rascal Flatts

Mr[K]id | 20:37 | 0 nhận xét







I can hear the truck tires coming up the gravel road
And it’s not like her to drive that slow, nothings on the radio
Footsteps on the front porch, I hear my doorbell
She usually comes right in, now I can tell

Here comes goodbye, here comes the last time
Here comes the start of every sleepless night
The first of every tear I’m gonna cry
Here comes the pain, Here comes me wishing things would never change
And she was right here in my arms tonight, but here comes goodbye

I can hear her say I love you like it was yesterday
And I can see it written on her face that she had never felt this way
One day I thought I’d see her with her daddy by her side
And violins would play here comes the bride

Here comes goodbye, here comes the last time
Here comes the start of every sleepless night
The first of every tear I’m gonna cry
Here comes the pain, Here comes me wishing things would never change
And she was right here in my arms tonight, but here comes goodbye

Why does it have to go from to good to gone?
Before the lights turn on, yeah and you’re left alone
All alone, but here comes goodbye

Oh-oh-oh-oh

Here comes goodbye, here comes the last time
Here comes the start of every sleepless night
The first of every tear I’m gonna cry
Here comes the pain, Here comes me wishing things would never change
And she was right here in my arms tonight, but here comes goodbye

Sống là Không Chờ Đợi

Mr[K]id | 20:32 | 0 nhận xét

"Bạn tôi mở ngăn tủ của vợ và lấy ra một gói nhỏ được gói kỹ càng trong lớp giấy lụa. Anh bảo: Đây không phải là một gói đồ bình thường, đây là một chiếc áo lót thật đẹp... Anh vứt lớp giấy bọc và lấy ra chiếc áo lót mịn màng, rồi nói: Tôi mua chiếc áo này tặng cô ấy vào lần đầu tiên chúng tôi sang New York, cách đây 8-9 năm nhưng cô ấy chưa bao giờ mặc! Cô ấy muốn dành cho một dịp nào đặc biệt, vậy thì hôm nay tôi nghĩ là dịp đặc biệt nhất rồi... Anh đến cạnh giường và đặt chiếc áo ấy cạnh những món đồ mà tí nữa đây sẽ được bỏ vào áo quan. Vợ anh vừa mới qua đời...

Quay sang tôi, anh bảo: "Đừng bao giờ giữ lại một cái gì để chờ dịp đặc biệt cả... Mỗi ngày sống là một dịp đặc biệt rồi...".

Tôi suy đi nghĩ lại câu nói này và nó đã làm thay đổi cuộc đời tôi...

Bây giờ tôi đọc sách nhiều hơn trước và bớt thời gian dọn dẹp nhà cửa. Tôi ngồi trước mái hiên mà ngắm cảnh chứ không buồn để ý đến cỏ dại mọc trong vườn... Tôi dành nhiều thời gian cho gia đình và bạn hữu hơn là cho công việc. Tôi hiểu rằng cuộc đời là những cảm nghiệm mà mình phải nếm... Từ ngày ấy tôi không còn cất giữ một cái gì nữa... tôi đem bộ ly pha lê ra sử dụng mỗi ngày, tôi mặc đồ mới để đi siêu thị hay bất cứ nơi nào khi tôi cảm thấy thích... Tôi không còn dành nước hoa hảo hạng cho những dịp đại tiệc, tôi xức bất kỳ khi nào tôi muốn...

Những cụm từ như "một ngày gần đây" hay "hôm nào" đang bị loại khỏi vốn từ vựng của tôi. Điều gì đáng bỏ công thì tôi muốn xem, muốn nghe, muốn làm ngay bây giờ. Tôi không biết chắc là vợ của bạn tôi sẽ làm gì nếu cô ấy biết trước rằng mai đây mình không còn sống nữa (một ngày mai mà tất cả chúng ta xem thường). Tôi nghĩ rằng cô ấy hẳn sẽ mời mọi người trong gia đình, mời bạn bè thân thích đến nhà chơi... có thể cô sẽ gọi điện thoại cho vài người bạn cũ và làm hoà hay xin lỗi về những chuyện bất hoà trước đây...

Tôi đoán rằng cô ấy sẽ đi ăn các món Tàu (vì cô ấy rất thích thức ăn Tàu). Chính những chuyện vặt vãnh mà tôi chưa làm khiến cho tôi áy náy nếu tôi biết rằng thì giờ tôi còn rất có hạn. Tôi sẽ rất áy náy vì tôi không đi thăm một vài người bạn mình cần phải gặp mà cứ hẹn lần hồi, áy náy vì thường không nói với những người thân của mình rằng mình yêu thương họ... áy náy vì mình chưa viết những lá thư mà mình dự định "hôm nào" sẽ viết.

Giờ đây, tôi không chần chờ gì mà không hẹn lại và không giữ điều gì có thể đem lại niềm vui và nụ cười cho cuộc sống chúng tôi. Tôi tự nhủ rằng mỗi ngày là một dịp đặc biệt. Mỗi ngày, mỗi giờ, mỗi phút... đều đặc biệt cả.

Nếu bạn đọc được bản văn này ấy là vì một ai đó muốn điều hay cho bạn, và vì bạn cũng có quanh mình những người bạn quý yêu. Nếu bạn quá bận đến độ bạn không thể dành ra vài phút để copy và gởi bản văn này đến cho ai khác, rồi tự nhủ "mai mốt tôi sẽ gửi" thì mai mốt đó có thể là một ngày thật xa hoặc là bạn sẽ không bao giờ gửi được...

Nếu ai đã có lần
Một mình trước biển
Sẽ thấy con người nhỏ bé làm sao
Nhìn những con sóng dữ thét gào
Mới hiểu được vì sao mình tuyệt vọng

Nếu ai đã có lần
Bất cần sự sống
Hãy đón hạt sương mai trên một cành hoa
Ngắm nụ cười của lứa đôi vừa được làm mẹ, làm cha
Sẽ hiểu được vì sao chúng ta cần phải sống

Nếu ai đã có lần
Thấy giữa lòng khoảng trống
Hãy hiểu rằng trong vũ trụ kia còn có những lỗ đen
Ai rồi cũng sẽ phải quen
Với những phút giây long mình trống vắng

Nếu ai đã có lần
Nghe lòng cay đắng
Nghe xót xa sau một cuộc chia tay
Hãy vui lên vì trong cuộc đời này
Sau một cuộc chia tay là khởi đầu rất mới

Nếu ai đã có lần
Cảm thấy mình chưa hiểu
Thật nhiều điều đang có ở chung quanh
Hãy cứ cười lên vì đời vẫn màu xanh
Cuộc sống chỉ thú vị khi vẫn còn khám phá

Nếu ai đã có lần
Sống trong vất vả
Giữa những vòng đời hối hả trôi nhanh
Sẽ thấy yêu sao những phút thanh bình
Ngoài khung cửa nghe bình minh chim hót

Nếu ai đã có lần
Thấy lòng dịu ngọt
Trước một nụ cười, một ánh mắt, một vòng tay
Hãy chẳng cần đi tìm khắp đó đây
Vì hạnh phúc đơn giản là vậy đó."

Building Windows Applications in VB.NET

Mr[K]id | 05:03 | 0 nhận xét

In Visual Basic .NET, the technologies that enable you to create "standard" windows applications are part of the .NET Framework, available to any .NET language. This is a huge change from earlier versions of Visual Basic. Learn what's different -- and how you can take advantage of it.


Chapter 3: Building Windows Applications


In This Chapter



  • The Way Things Were

  • The Windows Forms Model

  • Handling Events in .NET

  • Coding Without Control Arrays

  • Configuring Your Form for Resizing

  • Programming Without Default Form Instances

  • Working with Multiple Forms in VB .NET

  • In Brief


The Way Things Were


For most of Visual Basic's history, you did not need to specify you were building a rich-client application—all the applications you built were rich-client apps. Web development has never been the purpose of Visual Basic. This focus on developing stand-alone or client/server applications with a Windows user interface created a very tight bond between the VB language and the forms engine within it. There was no need to distinguish between the language and the tools for building an interface in VB6, but there certainly is in .NET.


In Visual Basic .NET, the technologies that enable you to create "standard" windows applications are part of the .NET Framework, available to any .NET language. This is a huge change from the way things were. In each of the following sections, before going into detail on how the new Forms technology works in Visual Basic .NET, I briefly describe some of the relevant details about Visual Basic 6.0 forms.



The Windows Forms Model


Forms in Visual Basic 6.0 were distinct files from other types of code (such as modules and classes) stored in two parts—a .FRM file that contained the code and the layout of the form and a .FRX file, which was a special kind of resource file that held any embedded resources needed by the form. When you designed a form using the visual tools, controls were added to forms and properties were set (such as the size and position of various controls) without any visible effect on your code. Changing the position of a button would change some hidden (not shown in the IDE at least) text (shown below for a simple one button "Hello World" application) that you could access and change using a text editor, but all of these properties were not part of your code. Setting a property in code was therefore very different than setting it through the visual interface.


Listing 3.1 The Code Behind a Visual Basic 6.0 Form


VERSION 5.00
Begin VB.Form Form1
Caption = "Form1"
ClientHeight = 3090
ClientLeft = 60
ClientTop = 450
ClientWidth = 4680
LinkTopic = "Form1"
ScaleHeight = 3090
ScaleWidth = 4680
StartUpPosition = 3 'Windows Default
Begin VB.CommandButton Command1
Caption = "Hello World"
Default = -1 'True
Height = 495
Left = 840
TabIndex = 0
Top = 480
Width = 1335
End
End
Attribute VB_Name = "Form1"
Attribute VB_GlobalNameSpace = False
Attribute VB_Creatable = False
Attribute VB_PredeclaredId = True
Attribute VB_Exposed = False

This special area of the form would also contain object references (in the form of GUIDs) for any ActiveX controls you used. Although editing the .FRM file directly was not encouraged, that was exactly what you had to do to fix a corrupt form.


Forms in .NET change everything just described. Forms are no longer "special" files; they are just code (.VB files in .NET), although they certainly can have associated resource files with them. Editing the properties of the form or of the controls on the form does not add hidden text to the form file; it generates real VB .NET code that sets the properties in the same way that you would in your own code. If you follow along with me and create a sample VB .NET form, you can explore the new forms designer and browse the code generated by your visual editing.


Building a Hello World Sample


First, go ahead and fire up Visual Studio .NET. Although it is possible to create Visual Basic .NET applications without using any IDE (another example of how VB has changed in its move to .NET), this book assumes that you have at least VB .NET Standard Edition and are therefore using the Visual Studio IDE.


Once it is loaded, you should see a start page. This start page has a few tabs and several different areas of information, but the main area (which is displayed by default) has all of the functionality you need at this point, including a list of recently opened projects and a New Project button. Click the New Project button, or select File, New, Project from the menu to bring up the New Project dialog box.


If you are new to Visual Studio .NET, this dialog box contains a lot more options than the equivalent from Visual Basic 6.0, including the capability to create Web Services, Windows Services, Console Applications, and more. For now though, pick the standard project for creating a new Windows Application: Windows Application. Selecting this project type (and picking a name and location, and then clicking OK) creates a new solution containing a single project that contains one blank Windows form and a code file called AssemblyInfo.vb. At this point, if you look around the Visual Studio .NET IDE, you will see an interface that is somewhat similar to Visual Basic 6.0, but many things have changed. In the first chapter of this book, I covered the IDE, detailing the key changes from Visual Basic 6.0 and many of the important features.


Moving along with this quick sample, you will build the application's user interface by placing a button onto the form. To work with the form, you need to use its design view, which is accessed through the same steps as in VB6. Double-click the form (in the Solution Explorer) to bring it up in the design view or right-click it and pick View Designer (this was View Object in VB6, but the meaning is the same) from the context menu.


Once you have the form's design view up, you can use the toolbox to select controls and place them onto your form. The toolbox looks a little different from the one in VB6. It has sliding groups to categorize all the different types of controls and lists the controls with an icon and text by default. It works a little differently as well. When you worked with the toolbox in Visual Basic 6.0, you had two choices of how to interact with it:



  • You could double-click a control and a new instance of that type of control would be added to the form with a default size and location.

  • You could also select a control and then click the form to set the top-left location and drag an outline out to represent the size of the control.

In the Windows forms designer, you have those two methods of placing a control and an additional option:


  • You can drag a control from the toolbox onto the desired location on your form and it will be placed at that position with a default size.


Using any one of the three possible methods, place a single button from the toolbox onto the form. It is a minor change, but it is worth noting that the CommandButton control from Visual Basic 6.0 has changed to the Button control in VS .NET 2002 and 2003. Just like in Visual Basic 6.0, you can double-click this new button to start writing an event handler for its most common event (in this case Click). All you want to do is pop up a message box, which you can do with the exact same line of code that you would use in Visual Basic 6.0 (see Listing 3.2).


Listing 3.2 Hello World Does Not Look Too Different in .NET


Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
MsgBox("Hello World!")
End Sub

You can run the project at this point if you want; F5 works fine for that purpose or you can select Start from the Debug menu. The real reason for building this form was to look at the code generated by your actions in the designer.


Exploring the Designer Generated Code


Switch to the code for the form (right-click the form in the designer or the Solution Explorer and select View Code) and you will see your button's click procedure and an area called Windows Form Designer generated code, as shown in Figure 3.1.


Figure 3.1Figure 3.1 Regions allow you to hide blocks of code.



That area is a region, a new feature of the code editor in Visual Studio .NET that allows you to collapse areas of code down to a single line to simplify the experience of browsing code. We discussed regions in Chapter 1, but all you have to know now is that the designer (the visual tool for creating forms) has used this feature to hide all of the code that it generated as you built the form. As a rule, you are not supposed to go into this area of code, which is why it is hidden by default, but you should at least understand the code in this area. In some cases, you might even need to change it. You can expand the designer code region by clicking the plus symbol next to the region name.


Inside the region, you will find a few key elements:



  • A constructor for the form (a Sub New())

  • A Dispose procedure

  • Declarations of all of the controls on the form

  • A sub called InitializeComponent


    The Constructor and the Dispose routines are new to Visual Basic .NET, but they are relatively equivalent to the Class_Initialize and Class_Terminate events of Visual Basic 6.0 classes. The constructor is called when an instance of your form is created; the dispose is called before the form is destroyed. The real meat of the designer-generated code is the other two code elements—the list of declarations for all of the controls on the form and the InitializeComponent routine that sets up the properties of the controls on the form and of the Form itself. You did not set up many controls or even change many properties when creating this simple sample, but let's take a look at the generated code, shown in Listing 3.3.


Listing 3.3 In VB .NET, You Can View and Even Edit All the Code that Builds Your Form's Interface


'NOTE: The following procedure is required by the Windows Form Designer
'It can be modified using the Windows Form Designer.
'Do not modify it using the code editor.
Friend WithEvents Button1 As System.Windows.Forms.Button
<System.Diagnostics.DebuggerStepThrough()> _
Private Sub InitializeComponent()
Me.Button1 = New System.Windows.Forms.Button
Me.SuspendLayout()
'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(96, 88)
Me.Button1.Name = "Button1"
Me.Button1.TabIndex = 0
Me.Button1.Text = "Button1"
'
'Form1
'
Me.AutoScaleBaseSize = New System.Drawing.Size(5, 13)
Me.ClientSize = New System.Drawing.Size(292, 273)
Me.Controls.Add(Me.Button1)
Me.Name = "Form1"
Me.Text = "Form1"
Me.ResumeLayout(False)
End Sub

The comment on the top of this routine lets you know that you can modify anything in here by using the visual designer, and that you should not change the code directly. This is pretty good advice, but let's ignore it for a moment and see what happens. If you look at lines 12-15 in Listing 3.3, you can see that they are setting the properties of the button, including the size. If you add some of your own code in there, even something as simple as outputting some text to the debug window, it could produce surprising results.


In this case, just adding a line (see Listing 3.4) causes the Windows Form Designer to fail when trying to parse the code, producing the helpful little error message shown in Figure 3.2.


Listing 3.4 Editing the Windows Forms Designer Generated Code May Produce Unexpected Results


'
'Button1
'
Me.Button1.Location = New System.Drawing.Point(96, 88)
Me.Button1.Name = "Button1"
Debug.WriteLine("Testing!")
Me.Button1.TabIndex = 0
Me.Button1.Text = "Button1"

Figure 3.2Figure 3.2 The Windows Forms Designer does not deal well with someone changing its code.



Other, less fatal, changes to the code are often undone the next time you change something in the designer (because the InitializeComponent procedure is regenerated), which can be quite frustrating. Code generators (such as the designers in Visual Studio .NET) work well in many situations, but when they have to support round tripping (where the code isn't just generated once; it is read back in and used by the designer whenever the form needs to be displayed), they tend to be very fragile. In this case, you cannot make code changes to most of the designer-generated area. The place where you can change code is in the constructor; you can freely add code after the call to InitializeComponent as long as you do not remove that line! The best bet is to ignore all of the code inside this special region, other than the constructor, and make all of your property changes through the visual interface. Now let's go back to the button's click procedure and take a closer look at how .NET is handling events.


Handling Events in .NET


Event handling has changed, for the better, in .NET. I never really thought anything of it, but event procedures in Visual Basic 6.0 were attached to the appropriate object and event based solely on the procedure's name. This reliance on names meant that if you had already created and written code for CommandButton1_Click and you renamed your button to the more meaningful saveFile, your event procedure would no longer be attached to this button.


If event handling is no longer based on procedure names, how do you connect a specific event handler with an object's event? There are two ways; one combines the familiar WithEvents keyword in your variable declarations with a new keyword Handles, and the other dynamically connects an object's event to an event handling procedure at runtime.


Using WithEvents and the Handles Keyword


Although event handling in VB .NET has changed, as I described, using the Handles keyword is the closest model to pre-.NET Visual Basic and it is the model used by default by the Windows forms designer. Objects, such as controls, that expose events are declared using the WithEvents keyword, like they were in Visual Basic 6.0, and event procedures provide a Handles myObj.myEvent clause after the procedure declaration. Those two parts, the Handles and WithEvents, wire up a specific event handling procedure.


Returning to the first example, a simple button on a form, look at the code generated by the Windows forms designer to see how the designer wired the Button's Click event to a code procedure. The first line to look at is the declaration of the button itself:


Friend WithEvents Button1 As System.Windows.Forms.Button

The button is declared using the WithEvents keyword, which is required if you want to use the Handles keyword on the event handling procedure. Only having both will make the proper connection between this object (the button) and the event procedure. Next, you double-click the Button1 and the Windows forms designer automatically creates a new event procedure for the default event (Click). Controls can specify one of their events to be the default. If they do, the Windows forms designer will assume you want to work with that event when you double-click the control. The designer knows that the button was declared using the WithEvents keyword, so it creates the procedure declaration with Handles Button1.Click appended to the end (see Listing 3.5).


Listing 3.5 Designer Generated Event Handlers Use the Handles Keyword


Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
MsgBox("Hello World!")
End Sub

Up to this point, the syntax might be a little different, but the general idea is the same as in Visual Basic 6.0. The only change, the addition of the Handles keyword, is just a way to get around relying on the name of your event handling procedure. Even using WithEvents and Handles though, there is a new feature built into this method of handling events. It is possible to specify that a specific event procedure handle more than one event. If you were to add a second button to the form, (automatically named Button2) and to double-click it, the Windows forms designer would create a second event procedure (see Listing 3.6).


Listing 3.6 The Windows Forms Designer Automatically Creates a Handler for the Default Event When You Double-Click a Control


Private Sub Button2_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button2.Click
End Sub

This procedure declaration is followed by Handles Button2.Click, but you could instead modify the first Click procedure to handle both buttons' Click events, as shown in Listing 3.7.


Listing 3.7 Listing More than One Object's Events After a Procedure Declaration Allows You to Consolidate Code


Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click, Button2.Click
MsgBox("Hello World!")

End Sub

Now, when either button is clicked, the same code will run. Any number of events can be handled by the same event procedure, assuming that all of the events have the same signature (the same set of arguments to their event procedures). It is also possible to have a single event handled by multiple procedures (see Listing 3.8) by having that event specified in multiple Handles clauses.


Listing 3.8 One Event, Such as a Button's Click, Can be Handled by Multiple Routines


Private Sub ClickEvent1( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button2.Click
MsgBox("ClickEvent1")
End Sub

Private Sub ClickEvent2( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button2.Click
MsgBox("ClickEvent2")
End Sub

When Button2 is clicked, the code in both ClickEvent1 and ClickEvent2 is executed. You will use the first concept (multiple events being handled by a single event handler) more often than the second (multiple handlers for a single event), but it is good to know that the functionality exists if you need it. In the case of multiple events all being handled by a single event handler, you will likely need to know which specific control is raising (firing or causing) the event. For most events, the object that raises the event is passed in as the first parameter (usually named "sender") to the event procedure. The sender parameter is typed as an object, which means that you have to convert it into a more useful type (such as a Control or a Button) before you can work with it. Listing 3.9 shows a sample event procedure that is handling the Click event of 10 buttons; it casts (views an object as a different type) the sender parameter from Object to Button to determine the Button's text (caption).


Listing 3.9 If You Handle the Events of Many Different Objects, the Sender Parameter Tells You which Object Caused the Current Event


Private Sub LotsOfButtons( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click, Button2.Click, _
Button3.Click, Button4.Click, _
Button5.Click, Button6.Click, _
Button7.Click, Button8.Click, _
Button9.Click, Button10.Click
Dim clickedBtn As Button
If TypeOf sender Is Button Then
clickedBtn = DirectCast(sender, Button)
MsgBox(clickedBtn.Text)
End If
End Sub

It is worth noting, although perhaps a bit confusing, that you could have also written this routine using Control instead of Button, and this alternative is shown in Listing 3.10.


Listing 3.10 All Windows Forms Controls Inherit from Control, so a Variable of that Type Can Be Used to Hold Any Control on Your Form


Private Sub LotsOfButtons( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click, Button2.Click, _
Button3.Click, Button4.Click, _
Button5.Click, Button6.Click, _
Button7.Click, Button8.Click, _
Button9.Click, Button10.Click
Dim clickedCtrl As Control
If TypeOf sender Is Control Then
clickedCtrl = DirectCast(sender, Control)
MsgBox(clickedCtrl.Text)
End If
End Sub

The reason this works, and it does work, is due to the way in which Windows Forms controls have been written. All Windows Forms controls share the same base class, System.Windows.Forms.Control, and that class provides them with a set of common properties, events, and methods. Text is one of those common properties, so you can cast to Control instead of Button and everything will still work. What does that mean to you? It means you can write code to handle any control on a form and you never have to know what type of control it is. Without casting it to a specific type of control, you can work with any of the common properties available on the Control class including position and size properties, color properties, and many more. Combining the new flexibility in event handling with this common control class, there is a lot you can accomplish using WithEvents and handles. There are a few cases though, when even more flexibility is required, and that is where the other method of event handling comes in.


Wiring Up Events Manually with AddHandler/ RemoveHandler


The WithEvents/Handles method of event handling is designed for when you know at design time which controls and which event handling procedures you are dealing with. If you are going to be working with objects and event procedures in a more dynamic fashion, you can use the AddHandler and RemoveHandler statements to connect an object's event to an event procedure at runtime. This is more of an advanced technique, and it will not likely be necessary in most applications, but here is a basic example to illustrate how these statements could be used. In this example, there is a Button and a CheckBox (set to look like a button) on an otherwise empty form (see Figure 3.3). When the CheckBox is pressed (see Listing 3.11), the button's Click event is attached using AddHandler to a simple event handler that displays a MsgBox. When the CheckBox is in its up position, the button is detached from its event handler using RemoveHandler.


Figure 3.3Figure 3.3 The check box on this form, which is using the new toggle button appearance, turns event handling on and off for the button.



Listing 3.11 The CheckedChanged Event of the Check Box Is Used to Add and Remove an Event Handler for the Button's Click Event


Private Sub CheckBox1_CheckedChanged( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles CheckBox1.CheckedChanged
If CheckBox1.Checked Then
AddHandler Button1.Click, _
AddressOf myClickHandler
Else
RemoveHandler Button1.Click, _
AddressOf myClickHandler
End If
End Sub

Private Sub myClickHandler( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs)
MsgBox("Event Handled!")
End Sub

Adding and removing an event handler is a more useful technique with non-form classes that raise events, but the procedure is the same.



Dynamic Event Handling


The AddHandler/RemoveHandler statements open up a completely new form of event handling, one that wasn't available in Visual Basic 6.0. There are many occasions where you will find yourself dynamically creating objects such as controls, but also including such things as forms, database objects, socket objects for TCP/IP communication, and more. By using AddHandler, you can still trap events from these objects even though you never declared them using WithEvents.


Behind the scenes, AddHandler and RemoveHandler are doing work with the delegate related Framework classes, wrapping the functionality of adding and removing additional methods (event handlers) to the same delegate (event). If you need to, you can still work natively with the System.Delegate class instead of, or in addition to, using AddHandler and RemoveHandler.


Coding Without Control Arrays


One of the more noticeable changes for a Visual Basic 6.0 developer who is getting started in Windows forms is the lack of control arrays. This feature of pre-.NET VB allowed you to configure a set of controls with a single name by assigning index values to each control. Once a control array was created, a single event procedure could be used to handle the events of all the controls in the array and you could also loop through the controls in an array based on index. These features made control arrays useful for a great many projects, but I mostly remember using this feature to handle groups of option buttons (radio buttons in .NET). Consider this form in VB6 (see Figure 3.4), which displays a six-item option button (radio button) collection using a control array. A single event handler (see Listing 3.12) can be written for this array that will run whenever any of the options are selected, or the array can be looped through to find the one option button with a Value = True.


Listing 3.12 VB6 Event Handler for an Option Button Control Array


Private Sub optFruit_Click(Index As Integer)
MsgBox "Selected Item: " & optFruit(Index).Caption
End Sub

Figure 3.4Figure 3.4 A group of options buttons on a VB6 form can all be part of a control array.


Due to the changes in event handling, allowing multiple objects' events to be mapped to the same event handler, achieving the same effect in Windows forms is not impossible, but it is not quite as simple as it was in VB6. Combining the event handling features of .NET with the use of a standard array, here is a walkthrough of handling some radio buttons on a .NET Windows form. This example creates an array to hold a set of radio buttons and shows you how you can use that array along with a shared event handler to determine which option button is currently selected. If you follow along with these steps, you can try out the code for yourself.



  1. Create a new Visual Basic .NET Windows application.

  2. A blank Form1 will be created and opened in Design View. Select the form and then drag a new radio button onto it from the toolbox.

  3. Copy and paste the radio button four times onto the form. This is likely the fastest way to end up with five radio buttons, but you can also drag four more radio buttons from the toolbox.

  4. Add a label to your form.

  5. Double-click one of the radio buttons to jump into its CheckedChanged event (see Listing 3.13) and modify the Handles clause to include all five of the radio buttons' events.


    Listing 3.13 Creating an Event Handler for All Five Radio Buttons


    Private Sub RadioButton1_CheckedChanged( _
    ByVal sender As System.Object, _
    ByVal e As System.EventArgs) _
    Handles RadioButton1.CheckedChanged, _
    RadioButton2.CheckedChanged, _
    RadioButton3.CheckedChanged, _
    RadioButton4.CheckedChanged, _
    RadioButton5.CheckedChanged

    End Sub


  6. Declare an array of radio buttons as a private member variable in your form (put the declaration anywhere in your code outside of a procedure):


    Dim radioButtons(4) As RadioButton

  7. Declare an integer private member variable as well:


    Dim selectedOption As Integer = 0


  8. Add code into the constructor of the form (the sub New() procedure contained within the Windows Forms Designer generated area) to fill up the array with the radio buttons (see Listing 3.14).


    Listing 3.14 Filling Up Your Own Radio Button Array


    Public Sub New()
    MyBase.New()

    'This call is required by the Windows Form Designer.
    InitializeComponent()

    'Add any initialization after the InitializeComponent() call
    radioButtons(0) = RadioButton1
    radioButtons(1) = RadioButton2
    radioButtons(2) = RadioButton3
    radioButtons(3) = RadioButton4
    radioButtons(4) = RadioButton5
    End Sub


  9. Finally, write code into the shared CheckedChanged event handler that will loop through the radio button array and determine the currently selected option (shown in Listing 3.15). Store the appropriate array index into selectedOption and change the Text property of the label control.


    Listing 3.15 Loop Through the Radio Buttons and Determine which One Is Clicked


    Private Sub RadioButton1_CheckedChanged( _
    ByVal sender As System.Object, _
    ByVal e As System.EventArgs) _
    Handles RadioButton1.CheckedChanged, _
    RadioButton2.CheckedChanged, _
    RadioButton3.CheckedChanged, _
    RadioButton4.CheckedChanged, _
    RadioButton5.CheckedChanged
    Dim i As Integer = 0
    Dim found As Boolean = False
    While i < radioButtons.GetLength(0) And Not found
    If radioButtons(i).Checked Then
    found = True
    selectedOption = i + 1
    Label1.Text = CStr(selectedOption)
    End If
    i += 1
    End While
    End Sub

If you were to run this code, you would see the label changing every time a different option was selected. The flexibility of event handling in .NET allows you to work with a set of five radio buttons without having to have five different event handlers.


Configuring Your Form for Resizing


Every time I built a resizable form in Visual Basic 6.0 (which includes every form I built except for the simplest of dialog boxes), I had to write code into the form's Resize event.


I had to decide how I wanted each control to adjust to the new size of the form, what size was too small for my interface to be usable, and I had to remember to check if the form had been minimized before trying to do any resizing. This code was not particularly hard to write, and after 50 or 60 forms I could do it without much thought, but it still took time and effort for every form I created. In Windows forms, a variety of features have come together to allow you to configure your controls for auto-resizing without having to write a single line of code. By combining the docking and anchoring features with the careful use of panels, you can set your form up to resize in almost any way you can imagine. If you add in the auto-scroll feature, you can even have parts of the form that do not resize at all, but instead extend right off the visible area of the form.



Using the Layout Event in Windows Forms


This section is all about avoiding the code you used to have to write into your Resize event handler, but even if you did write code, it wouldn't be in the same event handler in .NET. A new event, Layout, is available in Windows forms, and if you need to write code that adjusts the form after a resize, the Layout event is the best place for it.



The following sections explain how each of these three features works and how the use of panels can increase your flexibility of control arrangement. Once you have learned about all the features, the chapter will detail a few of the more common form layout scenarios, showing you how to set them up for proper resizing.


Using Docking to Handle Resizing


Docking windows and toolbars have been in use for quite some time, so the general concept is not new; a docked item is attached to one of the edges of its container (such as a form). Consider a form that contains only a single ListBox control. If you set the ListBox's Dock property to Left (see Figure 3.5), the height of the control will be fixed to the height of the form's client area (causing the list box to fill the form from top to bottom), while the position of the control will be locked to the left side of the form. The only thing you can change about the size of the list box at this point is its width, controlling how far out from the left side it extends. Docking to the right is essentially the same; the list box becomes attached to the right side of the form, but you can still change its width as desired. Docking to the top or bottom will cause the width to be fixed to fill the width of the form, but the height of the control can still be modified.


Figure 3.5Figure 3.5 Docking a control to the left makes it stick to the left side, while filling the vertical space of the container.


In addition to docking to one of the four sides, controls also support a fifth (sixth if you count None for no docking) docking setting, Fill. If you set the Dock property to Fill, that control becomes attached to all four sides of the container, adjusting itself automatically as the form is resized. You cannot adjust any size or position settings for a control that has been docked to fill the container.


Remember that you are docking the control to its container, which in this example is the Form, but could be a container control such as a GroupBox or Panel. This flexibility leads to more layout options, as you will see later in the section on "Using Panels."


The container (form, panel, or other type of container control) has a DockPadding property, which allows it to specify a certain amount of padding between it and docked controls. The padding values can be specified individually for the four sides of the container, or an overall padding value that applies to all of the sides at once. If a container has specified a DockPadding value of 10, for example, a control docked to the left will be positioned 10 pixels away from the left edge. The DockPadding setting is great for creating a more visually pleasing user interface as it results in a border around the form while still enabling the automatic resizing of docked controls (see Figure 3.6).



Figure 3.6Figure 3.6 DockPadding allows you to dock, without sacrificing a bit of white space around the edge of your controls.


Docking gets a little more complicated when multiple docked controls are involved. If you dock more than one control to the same edge, the second control will dock alongside the first instead of directly to the container. Going back to the example with the ListBox on a form, you can try multiple docked controls to see what happens. If you docked the ListBox to the bottom and then added a new DataGrid to the form, setting its Dock property also to Bottom, you would have produced an interface similar to Figure 3.7, where the ListBox appears below the DataGrid.


Figure 3.7Figure 3.7 Multiple controls docked to the same side will stack instead of overlap.


Both of the controls are docked to the form and will resize as the form is resized. If you have controls docked to one or more sides of your container, and then you set another control's Dock property to Fill, the control set to Fill will be automatically sized to use all of the remaining area of the container. If you have multiple controls docked on a form, you might want to use the Splitter control. Splitter is a special Windows Forms control that, when docked between two other controls, allows you to resize the two controls at runtime. Using the Splitter control and a few other key controls, you can create a standard Explorer view form in a matter of minutes.


To add a splitter to your form, you need to be careful of the order in which you add your controls. Try adding a ListBox to an empty form, and docking it to the left. Then add a splitter control, and dock it to the left as well (it is by default). Finally, add a DataGrid control, dock it to the left as well, or set its dock property to Fill, and you will have a working example of using a splitter!


A little confusing? It can appear very complex, but the best bet is to try it out on your own, adding a variety of controls to a blank form and playing around with the various Dock/DockPadding settings.


Anchoring as an Alternative Resizing Technique


After docking, this has to be the coolest layout feature. Anchoring is a little simpler than docking, but it can be a powerful tool. Using a graphical property editor (see Figure 3.8), you can set the Anchor property for a control to any combination of Top, Left, Bottom, and/or Right.


Figure 3.8Figure 3.8 The property editor for anchoring is a nice little graphical control.


To anchor a control to a specific side means that the distance between the control and that side of its container becomes fixed. Therefore, if you anchor a control to a specific side and then resize the form, the control's distance from the anchored side(s) will not change. To maintain a constant position relative to one or more sides of your container, the control might have to be resized when the form's size changes.


By default, controls are anchored to the top and left, which makes them behave exactly as controls did in previous versions of Visual Basic. When you resize the form, they do not move or resize. If you want to create a TextBox that grows as you make your form wider, you can anchor it to the top, left, and right sides. If you want the TextBox to grow in height as well as width, anchor it to the bottom as well. Figure 3.9 shows a form with some anchored controls, and Figure 3.10 shows what happens when that form is resized. You will see a few more examples of how anchoring can be used to lay out your form in the samples throughout the rest of this book.



Figure 3.9Figure 3.9 Anchored controls maintain a fixed distance between themselves and the container edge(s) they are anchored to.


Figure 3.10Figure 3.10 As the form changes size, the controls move and resize automatically.


AutoScrolling Forms


Docking and anchoring are designed to resize your controls when the form is resized, but resizing the contents of your form is not always appropriate. In some cases there is a minimum size at which your form is usable, so resizing below that needs to be avoided. There are also situations when the content on your form is a fixed size, making resizing inappropriate. Windows forms provides a few additional features to allow you to deal with these situations. Forms have minimum/maximum height and width properties (allowing you to constrain resizing to a specific range of sizes) and the AutoScroll feature. AutoScroll allows a form to be resized by the users, but instead of shrinking the controls on the form, scroll bars appear to allow the users to view the entire form area even if they have resized the window. The form shown in Figure 3.11 is a perfect candidate for AutoScroll; it contains a large number of controls and buttons and cannot be resized using docking or anchoring.


Figure 3.11Figure 3.11 This form would be hard to resize, so the solution is to allow users to scroll.


If the user were to resize this form, making it smaller than the area required for all of its controls, the AutoScroll feature of Windows forms will save the day by adding horizontal and/or vertical scroll bars as required (see Figure 3.12).


Figure 3.12Figure 3.12 AutoScroll automatically adds scroll bars when the form becomes small enough to hide any part of any of the controls on the form.


In addition to the AutoScroll property, which you set to True to enable auto scrolling, there are two other properties, AutoScrollMargin and AutoScrollMinSize, that are used to configure exactly how scrolling occurs.


Using Panels


Panels enhance all of the other layout features discussed so far because they can act as a container for other controls, much like a form does. Because they are containers, panels have their own DockPadding property and all of the auto-scroll features described for forms. A control can be placed into a panel and anchored to the bottom-right corner of that panel, while the panel itself was docked or anchored to a specific location on a form. By combining panels with forms, you can design more complicated layouts that still support resizing. Panels are used in several of the examples in the next section.


Some Common Resizing Scenarios


Now that you have been told what docking, anchoring, and auto-scrolling are, here are a few forms that demonstrate using the new layout features.


A Standard One-Large-Control Dialog Box


A large control, such as TextBox, ListBox, or DataGrid, needs to resize properly on a Form with two buttons (OK and Cancel), as shown in Figure 3.13.


Figure 3.13Figure 3.13 Allowing the users to resize your form makes your application work better on a range of screen sizes.


If it were not for those two buttons, docking would be a possible answer, but anchoring saves the day here. Assuming a desired border around the form's contents of 10 pixels:



  • Position the large control with its top, left, and right edges 10 pixels in from the corresponding form edges. Note that you don't have to be exact about these positions, anchoring will lock the control in whatever place you put it. A precise border is just for aesthetics.

  • Add your two buttons to the bottom of the form, placing their bottom edge 10 pixels up from the bottom of the form. The right edge of one button should be 10 pixels in from the right edge of the form. Place the other button so that its right edge is five pixels away from the left edge of the first button.

  • Adjust the height of the large control so that its bottom edge is 10 pixels from the top of the two buttons.

  • Now, set the large control's Anchor property to "Top, Bottom, Left, Right" and both buttons' Anchor property to "Bottom, Right".


A Long List of Questions


You have a long list of questions that must be answered before a user can submit an order, and additional questions keep being added. There also needs to be an OK and Cancel button on the form; OK to move onto submitting the order, and Cancel to close the form and cancel the order.


AutoScroll is the key for this layout, either for the entire form or for a panel, depending on whether you want to keep the OK and Cancel buttons visible at all times or if you want the user to have to scroll down to find them.



  • For the first option (Figure 3.14), where you want the buttons to be visible at all times, set up your form just like in Example 3.1, but use a Panel control as the large control.

    Figure 3.14Figure 3.14 A panel allows you to restrict which parts of the form scroll and which parts are always visible.


  • Set the panel's AutoScroll property to True and then place all of your individual questions into the panel.

  • For the second option (Figure 3.15), set the Form's AutoScroll property to True and place all of your questions onto the form.

    Figure 3.15Figure 3.15 You can use the entire form surface for your scrolling area.



  • Add your OK and Cancel buttons at the very bottom of your form below all of the questions.



A Multi-Column Form


You have a form with multiple columns of text boxes, each with associated labels, a single large text box, and the OK and Cancel buttons at the bottom (see Figure 3.16).


Figure 3.16Figure 3.16 Multiple columns are trickier to resize.


This gets a little trickier because of the two columns at the top of the form, but panels can make it all work out.


  • Create a panel (mainPanel) that is tall enough to contain all of your controls for the top section of the form.

  • Create two more panels (rightPanel and leftPanel) and place them in the first panel you created.

  • Select one of new panels (rightPanel) and make its Dock property equal to Right; make the other panel's Dock property equal to Fill.

  • Now, leftPanel will always fill the space not taken by rightPanel, but there is no way (in the designer) to force those two panels to equally share the available space. Instead you have to go to code.

  • View the code for your form, and then select mainPanel from the object drop-down list (left side) and Layout from the event drop-down list (right side). Enter the code from Listing 3.16, assuming your panel names are mainPanel, rightPanel, and leftPanel, into the Layout event handler.


    Listing 3.16 Using Code to Make Two Panels Share the Available Space


    Private Sub mainPanel_Layout( _
    ByVal sender As Object, _
    ByVal e As System.Windows.Forms.LayoutEventArgs) _
    Handles mainPanel.Layout
    rightPanel.Width = mainPanel.Width \ 2
    End Sub



Note that I used the Layout event, which is a new event in Windows forms that was not available in Visual Basic 6.0. In Visual Basic 6.0, I would have used the Resize event, but Layout is actually more precise as it occurs when the position and size of controls within a container might need adjusting, as opposed to occurring upon every resize of the form. If a form were set to AutoScroll, for example, the Resize event would fire whenever the form was resized (as it should), but the controls inside the form would not need to be rearranged.


An Explorer-Style Application


You are attempting to produce an interface in the format of the Windows Explorer, Outlook, and other applications. This interface will have a TreeView along one side of the form and a ListView on the other, and have the capability to move the dividing line between the two controls to resize them (see Figure 3.17).


Figure 3.17Figure 3.17 The standard Explorer style of form layout.


This style of layout is easy to accomplish with the new features of Windows forms, but the specific order in which you add items to your form is important.



  • Starting with a blank form, add a TreeView control and set its Dock property to Left.

  • Add a Splitter control; it will automatically dock to the left and take its place along the right side of the TreeView.

  • Add a ListView control and set its Dock property to Fill.


That's it. The ListView will fill whatever space isn't being used by the TreeView and the Splitter will allow you to adjust the relative size of the two areas.


That is all of the sample resizing scenarios covered in this chapter, but that certainly is not the extent of layouts that can be created.


Programming Without Default Form Instances


Classes and objects existed in Visual Basic 6.0, but they were not as pervasive as they are in .NET. Objects are everywhere when you are developing in Visual Basic .NET, and that large change has lead to many small changes that can trip you up when you are coming from a VB6 background. One of the more commonly encountered problems for a VB6 developer is the lack of default form instances in .NET, but the term default form instance is confusing enough that I will need to go into more detail about the problem before we look at any solutions.


When you are dealing with classes and objects, it is helpful to think of a class as the blueprint of a house, whereas an object is an instance of a specific class and is more like an actual house that was built from the blueprint. In general, you don't work with classes, just like you don't live in blueprints. You create instances from your classes and it is those instances that get used throughout your applications. This is not a .NET issue; this is just how classes and objects work, even in VB6. Even in VB6, forms are considered classes, which is why you can create multiple copies (instances) of a single form in your VB6 code if you wish. The two snippets of code in Listings 3.17 and 3.18, assuming you have a Form1 in your project, would produce the same result (11 open copies of Form1) in VB6 or VB .NET. The only differences between these two examples are syntax issues; they are otherwise identical.


Listing 3.17 VB6 Code to Display 11 Copies of a Form


'VB 6 Code
Dim i As Integer
Dim myFrm As Form1

For i = 0 To 10
Set myFrm = New Form1
myFrm.Show
Next

Listing 3.18 The Very Similar VB .NET Code for Displaying 11 Copies of a Form


'VB .NET Code
Dim i As Integer
Dim myFrm As Form1

For i = 0 To 10
myFrm = New Form1()
myFrm.Show()
Next

In each case, the code examples created 11 new instances of the class Form1 and then called a method (Show) on each of those new instances. Code you wrote in VB6 that worked with multiple instances of a single Form class will probably work in .NET without too many changes, but consider this VB6 code:


Form2.Show
Form2.TextBox1.Text = "dfsdf"

That code would not work in .NET, because it is treating the class Form2 as if it were an instance of Form2. In Visual Basic 6.0 and earlier versions, a special default instance of each form is automatically created, and allows you to use the form's name to access this instance. What this means is that the Visual Basic 6.0 code Form2.Show has the effect of showing the "default" instance of Form2, but it doesn't work in Visual Basic .NET. If you want to show a form in VB .NET, you need to create an instance, writing code like this to make Form2 visible:


Dim myFrm As New Form2()
myFrm.Show()

This is a major behavioral change from VB6, but the difference in code is not extreme. The removal of default instances changes more than just the code to show a form though. The second part of the problem is that these special default form instances were global to your entire project in Visual Basic 6.0. Taking the two facts together means that (in Visual Basic 6.0 or earlier) you can refer to any form in your project from anywhere in your code and you will always be referring to the same instance of that form.


In Visual Basic .NET, if you need to access an instance of Form2 from some other part of your application (such as another form or a module), you need to pass the reference to Form2 around your application. The next section explores some of the ways in which you can work with multiple forms.


Working with Multiple Forms in VB .NET


The previous section described a major change in the forms model from VB6 to VB .NET—the removal of default form instances. This is not a major technical problem; programmers (including VB6 programmers) have been working without default instances of non-form classes for a very long time, but it is a big change if you are used to building Windows applications using VB6. The result of this change is that you need a reference to a particular instance of a form to be able to use it. I will start with a very simple example to illustrate the concept. I will create a new Windows application that contains two forms. Form1, which will be shown automatically when the project runs, will create and display an instance of Form2 when you click a button. To illustrate communication from one form to another, Form2 will also have a button, and it will change the caption of Form1 whenever it is clicked. To get things started, create the new project and add a new form.


Select File, New, Project from the main menu in Visual Studio .NET, and then pick a Visual Basic Windows Application to create. A form will be created with a default name of Form1. Add a second form by right-clicking the project and selecting Add, Add Windows Form from the menu that appears. Accept the default name of Form2 for the new form and click the Open button to finish the wizard.


Creating and Displaying an Instance of a Form


The first step is to add code to Form1 to create and display an instance of Form2. Add a button to Form1, leaving it with a default name of Button1. Now, double-click the button to enter its event procedure for the Click event. If you used the code shown in Listing 3.19, a new form would open every time you click the button, which is likely not the desired result.


Listing 3.19 Simple Code for Displaying a Form


Private Sub Button1_Click(ByVal sender As System.Object, _
ByVal e As System.EventArgs) Handles Button1.Click
Dim myForm As New Form2
myForm.Show()
End Sub

Instead, you will move the Form variable to a module level value, and then determine if it already exists in the Click event (Listing 3.20). Then, you will create the form if it does not already exist and show it either way.


Listing 3.20 Code That Will Create and Display Only One Copy of a Form


Dim myForm As Form2

Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
If myForm Is Nothing Then
myForm = New Form2
End If
myForm.Show()
End Sub

Using the myForm variable allows you to hang on to a reference to your newly created form. Hanging onto the reference returned from creating a new form is useful so that you can talk to this second form if need be. The main reason for using this variable though, is so that you can create and track a single instance of Form2, instead of creating a new one on every button click. Now, let's make Form2 talk back to Form1.


Communicating Between Two Forms


If you want Form2 to be able to communicate with Form1, you need to supply a reference to Form1. Once you do this, you will be set up for two-way communication, as both forms will be holding a reference to the other. The simplest way to accomplish this is to add a public variable (of type Form1) to Form2, like this:


Public Class Form2
Inherits System.Windows.Forms.Form

Public myCaller As Form1

Then, right after you create an instance of Form2 in the button click event (see Listing 3.21), you can set this property.


Listing 3.21 You Can Pass a Form Reference with a Property


Dim myForm As Form2

Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
If myForm Is Nothing Then
myForm = New Form2
myForm.myCaller = Me
End If
myForm.Show()
End Sub

If code in Form2 needs to access Form1, it can now do so through the myCaller variable. Add a button to Form2 and put this code into it, as shown in Listing 3.22.


Listing 3.22 Now that Form2 Has a Reference to Form1, it Can Access Form1's Properties


Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click
If Not myCaller Is Nothing Then
myCaller.Text = Now.ToLongTimeString
End If
End Sub

Clicking the button on Form1 will create an instance of Form2 and populate Form2's myCaller variable with a reference to Form1. Clicking the button on Form2 will access Form1 through the myCaller variable (if it was set) and change its window title. This was a very simple example of communicating between multiple forms, but there will be additional examples as part of the sample applications in Chapters 4 and 5. The next section covers creating and using a form as a dialog box.


Creating and Using a Form as a Dialog Box


Technically speaking, every window/form in an application could be called a dialog box. When I use the term, however, I am referring specifically to a window that is displayed to request some information from the users and return that information back to the application that displayed the dialog box. For the most part, the calling application does not care what happens between displaying the form and the user clicking OK or Cancel to close it; all it is concerned with is the information gathered by the dialog box. To illustrate how you can create a standard dialog box using Visual Basic .NET, this section walks you through the creation of a dialog box that is designed to allow the users to enter in an address (see Figure 3.18).


Figure 3.18Figure 3.18 An Address entry dialog box.


Setting Up Your Form


First, you create the sample application and form. Open a new project, a Visual Basic Windows Application, and add a new form named GetAddress. There should now be two forms in your project, which is exactly what you want because we will launch the GetAddress dialog box from Form1. Now, you need to set up the look of GetAddress to match the expected appearance of a dialog box. Set up four text boxes named txtStreet, txtCity, txtPostalCode, and txtCountry on your form and arrange them somewhat like the form shown in Figure 3.18. Now, add two buttons to your form, saveAddress and cancelAddress, with captions of OK and Cancel, respectively. The two buttons should be positioned in the lower-right corner. If you are planning to make your dialog box resizable, you will want to anchor the two buttons to bottom and right. Select the form itself (click any empty area of the design surface) and set its AcceptButton and CancelButton properties to the saveAddress and cancelAddress buttons. Setting these properties allows the users to use the Enter and Escape keys as the equivalent of OK and Cancel. The AcceptButton property also makes the saveAddress button into the default for the form, which causes it to be highlighted. So that you can tell what button was pressed to exit the form, you should also set the DialogResult property of both buttons. Set the DialogResult property for saveAddress to OK, and set it to Cancel for cancelAddress.


If you want your dialog box to be resizable, select the Sizable option for the FormBorderStyle property. For a fixed sized dialog box, you select FixedDialog for FormBorderStyle and set MinimizeBox and MaximizeBox both to False.


Once you have created your dialog box, the key to using it is to determine a method for putting starting data into the dialog box and for pulling out the information the user entered. You could access the various controls (the text boxes) directly, but I strongly advise against it. If you work directly with the controls, you will have to change that code if you ever modify the dialog box. Instead, I suggest one of two approaches. Either create a property procedure for each of the values you are exchanging (street, city, postal code, and country in this example) or create a new class that holds all of these values and then create a single property for that object.


This section shows you both methods; you can use whichever one you prefer. For the first case, using multiple properties, create a property for each of the four values you are dealing with, as shown in Listing 3.23.


Listing 3.23 You Can Insert and Remove Values from Your Dialog Box Using Properties


Public Property Street() As String
Get
Return Me.txtStreet.Text
End Get
Set(ByVal Value As String)
Me.txtStreet.Text = Value
End Set
End Property

Public Property City() As String
Get
Return Me.txtCity.Text
End Get
Set(ByVal Value As String)
Me.txtCity.Text = Value
End Set
End Property

Public Property PostalCode() As String
Get
Return Me.txtPostalCode.Text
End Get
Set(ByVal Value As String)
Me.txtPostalCode.Text = Value
End Set
End Property

Public Property Country() As String
Get
Return Me.txtCountry.Text
End Get
Set(ByVal Value As String)
Me.txtCountry.Text = Value
End Set
End Property

For now, these property procedures are just working with the text boxes directly. The value in using property procedures instead of direct control access is that you can change these procedures later, without affecting the code that calls this dialog box. The properties are all set up now, but to make the dialog box work correctly, you also need some code (shown in Listing 3.24) in the OK and Cancel buttons.


Listing 3.24 Don't Forget to Provide a Way to Close Your Forms


Private Sub saveAddress_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles saveAddress.Click
Me.Close()
End Sub

Private Sub cancelAddress_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles cancelAddress.Click
Me.Close()
End Sub

Although both button click events do the same thing, close the dialog box, the DialogResult property of each button is set appropriately so it will result in the correct result value being returned to the calling code. In the calling procedure, a button click event on the first form, you populate the dialog box using the property procedures, display it using ShowDialog(), and then retrieve the property settings back into the local variables. ShowDialog is the equivalent of showing a form in VB6 passing in vbModal for the modal parameter, but with the added benefit of a return value. ShowDialog returns a DialogResult value to indicate how the user exited the dialog box. The example in Listing 3.25 checks for the OK result code before retrieving the properties from the dialog box.


Listing 3.25 If Users Click OK, You Must Copy the Values Back, Otherwise You Don't Want to Change Anything Because They Must Have Clicked Cancel


Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click

Dim address As New addressDialog

Dim Street As String = "124 First Street"
Dim City As String = "Redmond"
Dim Country As String = "USA"
Dim PostalCode As String = "98052"

address.Street = Street
address.City = City
address.Country = Country
address.PostalCode = PostalCode

If address.ShowDialog = DialogResult.OK Then
Street = address.Street
City = address.City
Country = address.Country
PostalCode = address.PostalCode
End If
End Sub

The other method I mentioned, using a class to hold a set of values instead of passing each value individually, requires just a few modifications to the code. First, you need to create the class. Add a new class to your project, named Address, and enter the class definition shown in Listing 3.26.


Listing 3.26 With a Class being Used to Hold Multiple Values, You Can Add New Properties to it without Having to Change the Code to Pass it Around


Public Class address
Dim m_Street As String
Dim m_City As String
Dim m_PostalCode As String
Dim m_Country As String

Public Property Street() As String
Get
Return m_Street
End Get
Set(ByVal Value As String)
m_Street = Value
End Set
End Property

Public Property City() As String
Get
Return m_City
End Get
Set(ByVal Value As String)
m_City = Value
End Set
End Property

Public Property PostalCode() As String
Get
Return m_PostalCode
End Get
Set(ByVal Value As String)
m_PostalCode = Value
End Set
End Property

Public Property Country() As String
Get
Return m_Country
End Get
Set(ByVal Value As String)
m_Country = Value
End Set
End Property
End Class

This class is nothing more than a convenient way to package data into a single object, but it allows you to have only a single property procedure (Listing 3.27) in the dialog box and to simplify the calling code in Form1 (see Listing 3.28).


Listing 3.27 The Number of Properties Is Reduced to One if You Switch to Using a Class Versus Individual Properties on Your Form


Public Property Address() As address
Get
Dim newAddress As New address
newAddress.City = txtCity.Text
newAddress.Country = txtCountry.Text
newAddress.PostalCode = txtPostalCode.Text
newAddress.Street = txtStreet.Text
Return newAddress
End Get
Set(ByVal Value As address)
txtCity.Text = Value.City
txtCountry.Text = Value.Country
txtPostalCode.Text = Value.PostalCode
txtStreet.Text = Value.Street
End Set
End Property

Listing 3.28 A Single Property to Exchange Data Simplifies the Calling Code as well as the Form


Private Sub Button1_Click( _
ByVal sender As System.Object, _
ByVal e As System.EventArgs) _
Handles Button1.Click

Dim addr As New address
Dim address As New addressDialog

Dim Street As String = "124 First Street"
Dim City As String = "Redmond"
Dim Country As String = "USA"
Dim PostalCode As String = "98052"

addr.Street = Street
addr.City = City
addr.Country = Country
addr.PostalCode = PostalCode

address.Address = addr
If address.ShowDialog = DialogResult.OK Then
addr = address.Address
End If
End Sub

The simple addition of a return code when displaying a modal form makes it easier to implement dialog boxes within Visual Basic .NET, but the lack of default form instances can make all multiple form applications difficult.


In Brief


This chapter presented a detailed overview of the new Windows client development model in Visual Basic .NET. Here are the important points of this chapter:



  • Windows forms is the new forms model for Visual Basic. Although it is similar to the forms model for Visual Basic 6.0, it supports many new features.

  • In .NET, you can see and sometimes edit all of the code that creates and configures your user interface.

  • Event handling in .NET is no longer based on the name of the event-handler procedure, instead a new Handles keyword has been added.

  • Form layout is more powerful in .NET than in VB6 due to the addition of new features for docking and anchoring.

  • There are no default instances of forms in VB .NET, which means you cannot work with the form's name as if it were always available.

For more information on .NET, visit our .NET Reference Guide or sign up for our .NET Newsletter.

 
Copyright © 2011. Mr[K]id's Zone - All Rights Reserved
Have a nice day!