Chỉnh sửa thông báo DevExpress (XtraMessageBox)
thuvienwinform - Mình rất là không thích những đoạn mà xen lấn tiếng anh, tiếng việt. Điển hình là các thông báo. Mặc định các nút đề là tiếng anh(OK, Yes, No, Cancel,...) chúng ta nên việt hóa toàn bộ. Vừa dễ dàng cho người sử dụng, vừa có được giao diện đẹp.
Công việc này khá đơn giản. Tạo 1 lớp (class) là xong!
Chú ý: cần thêm DevExpress.Data; và DevExpress.XtraEditors; (Add Reference)
Sử dụng:
Khai báo đoạn này trong sự kiện nạp (Form_load), hay trong tệp Program.cs đều được:
Chú ý: using DevExpress.XtraEditors.Controls;
Vậy là xong rồi!
Công việc này khá đơn giản. Tạo 1 lớp (class) là xong!
Chú ý: cần thêm DevExpress.Data; và DevExpress.XtraEditors; (Add Reference)
using System; using System.Collections.Generic; using System.Linq; using System.Text; using DevExpress.XtraEditors.Controls; using DevExpress.Utils.Localization; namespace ThuVienWinform.ThongBaoDevExpress { //https://documentation.devexpress.com/#WindowsForms/CustomDocument1866 public class TuyChinhDevExpress : Localizer { public string Abort { set; get; } public string Cancel { set; get; } public string Ignore { set; get; } public string No { set; get; } public string Ok { set; get; } public string Retry { set; get; } public string Yes { set; get; } public TuyChinhDevExpress(string abort, string cancel, string ignore, string no, string ok, string retry, string yes) { this.Abort = abort; this.Cancel = cancel; this.Ignore = ignore; this.No = no; this.Ok = ok; this.Retry = retry; this.Yes = yes; } public override string GetLocalizedString(StringId id) { if (id == StringId.XtraMessageBoxAbortButtonText) return this.Abort; if (id == StringId.XtraMessageBoxCancelButtonText) return this.Cancel; if (id == StringId.XtraMessageBoxIgnoreButtonText) return this.Ignore; if (id == StringId.XtraMessageBoxNoButtonText) return this.No; if (id == StringId.XtraMessageBoxOkButtonText) return this.Ok; if (id == StringId.XtraMessageBoxRetryButtonText) return this.Retry; if (id == StringId.XtraMessageBoxYesButtonText) return this.Yes; return base.GetLocalizedString(id); } } }
Sử dụng:
Khai báo đoạn này trong sự kiện nạp (Form_load), hay trong tệp Program.cs đều được:
Chú ý: using DevExpress.XtraEditors.Controls;
Localizer.Active = new TuyChinhDevExpress("&Hủy bỏ", "&Hủy", "&Chấp nhận", "&Xác nhận", "&Được", "&Thử lại", "&Được");
Vậy là xong rồi!
Tối ưu hóa chương trình lớn gồm nhiều Form
thuvienwinform
Trích đoạn "Nếu làm theo cách này, chương trình của bạn dù nặng đến đâu thì cũng chỉ khác nhau ở thời gian Load thôi, chứ chạy thì mượt thôi rồi :))" haha
I. Vấn đề
Những chương trình "lớn" - nhất là liên quan tới quản lí đào tạo, quản lí các loại .... đều thường dùng 20 tới 30 Form..... Hầu hết các form được gọi đi gọi lại rất nhiều trong quá trình sử dụng (nhất là những form con trong thiết kế MDI) Như vậy sẽ rất ngốn RAM ... với phương thức "this.Hide()" sẽ không giúp giải phóng bộ nhớ RAM . và bạn sẽ không thể gọi "this.Close()" để đóng hẳn form này (vì nó sẽ làm toàn bộ chương trình đóng) --> Nói chung không có phương thức nào giải phóng RAM khi các form này được gọi.
Vậy hôm nay mình sẽ hướng dẫn các bạn cách tối ưu hóa những chương trình kiểu này :)
Rất đơn giản thôi
II. Thực hiện
Ví dụ ở đây mình tạo chương trình mẫu có 6 form : frmMain, frmSplash, frm1 --> frm4
Bây giờ thay vì mỗi lần gọi phải tạo 1 đối tương như kiểu :
Ưu điểm của việc này là làm 1 cái form kiểu Loading nhìn "rất chuyên nghiệp" và các winform đã khởi tạo luôn trong trạng thái "Sẵn sàng" , gọi .Show() 1 cái là lên luôn (chứ không có tình trạng nếu form nhiều Control quá thì load lâu nữa... vì nó load sẽ rồi)
+ DTO.cs
+ Trong Form Splash (Load) chỉ cần khởi tạo rất đơn giản (nhớ cái form là MdiParent phải khởi tạo trước nhé) --> Đúng nghĩa là Load nhé :))
Và từ giờ hãy tương tác với các Form theo biến static trong class Winform
Ví dụ ở form Main muốn Show frm1 chỉ cần gọi :
* Update dữ liệu
Giờ có 1 vấn đề là cần Update dữ liệu mỗi lần bật 1 form lên (Vì form mình đã load từ khi bật chương trình - bây giờ dữ liệu có thể đã bị sửa rồi ) :D
Nếu gọi theo cách truyền thống "mỗi lần gọi lại tạo 1 đối tương mới rồi Show" thì nó tự update là đương nhiên
Nhưng theo cách này bạn sẽ làm 1 công việc khá đơn giản là viết thêm 1 phương thức Update dữ liệu nữa rồi gọi theo mỗi lần gọi phương thức Show().
Ví dụ : frm1 mình có 1 GridView, cần được làm mới mỗi khi frm1 hiện.
Trong class frm1 mình viêt:
=> Mỗi lần Show Form 1 hãy kèm thêm 1 lệnh cập nhật
Vậy là xong rồi.... Có vẻ hơi dài dòng nhỉ ^^!
Nếu làm theo cách này, chương trình của bạn dù nặng đến đâu thì cũng chỉ khác nhau ở thời gian Load thôi, chứ chạy thì mượt thôi rồi :))
Trích đoạn "Nếu làm theo cách này, chương trình của bạn dù nặng đến đâu thì cũng chỉ khác nhau ở thời gian Load thôi, chứ chạy thì mượt thôi rồi :))" haha
I. Vấn đề
Những chương trình "lớn" - nhất là liên quan tới quản lí đào tạo, quản lí các loại .... đều thường dùng 20 tới 30 Form..... Hầu hết các form được gọi đi gọi lại rất nhiều trong quá trình sử dụng (nhất là những form con trong thiết kế MDI) Như vậy sẽ rất ngốn RAM ... với phương thức "this.Hide()" sẽ không giúp giải phóng bộ nhớ RAM . và bạn sẽ không thể gọi "this.Close()" để đóng hẳn form này (vì nó sẽ làm toàn bộ chương trình đóng) --> Nói chung không có phương thức nào giải phóng RAM khi các form này được gọi.
Vậy hôm nay mình sẽ hướng dẫn các bạn cách tối ưu hóa những chương trình kiểu này :)
Rất đơn giản thôi
II. Thực hiện
Ví dụ ở đây mình tạo chương trình mẫu có 6 form : frmMain, frmSplash, frm1 --> frm4
Bây giờ thay vì mỗi lần gọi phải tạo 1 đối tương như kiểu :
frmMain frm = new frmMain();Mình sẽ tận dụng form frmSplash ( 1 form load trước khi form Main hiện ra) để khởi tạo tất cả các đối tượng (mà ở đây là 5 form : frmMain, frm1--> frm4) (Không Show đâu nhé) và biến đối tượng được lưu vào 1 class có tên DTO.cs .
frm.Show()
Ưu điểm của việc này là làm 1 cái form kiểu Loading nhìn "rất chuyên nghiệp" và các winform đã khởi tạo luôn trong trạng thái "Sẵn sàng" , gọi .Show() 1 cái là lên luôn (chứ không có tình trạng nếu form nhiều Control quá thì load lâu nữa... vì nó load sẽ rồi)
+ DTO.cs
class Winform
{
public static frmMain MAIN;
public static frm1 FORM1;
public static frm2 FORM2;
public static frm3 FORM3;
public static frm4 FORM4;
}
+ Trong Form Splash (Load) chỉ cần khởi tạo rất đơn giản (nhớ cái form là MdiParent phải khởi tạo trước nhé) --> Đúng nghĩa là Load nhé :))
Winform.MAIN = new frmMain();
Winform.FORM1 = new frm1();
Winform.FORM2 = new frm2();
Winform.FORM3 = new frm3();
Winform.FORM4 = new frm4();
Và từ giờ hãy tương tác với các Form theo biến static trong class Winform
Ví dụ ở form Main muốn Show frm1 chỉ cần gọi :
Winform.FORM1.Show()Đơn giản đúng không ^^! Bây giờ nó sẽ tiết kiệm bộ nhớ đồng thời chạy nhanh hơn rất nhiều đấy :) (Vì mọi thức đều được Load trước khi dùng mà ^^!)
* Update dữ liệu
Giờ có 1 vấn đề là cần Update dữ liệu mỗi lần bật 1 form lên (Vì form mình đã load từ khi bật chương trình - bây giờ dữ liệu có thể đã bị sửa rồi ) :D
Nếu gọi theo cách truyền thống "mỗi lần gọi lại tạo 1 đối tương mới rồi Show" thì nó tự update là đương nhiên
Nhưng theo cách này bạn sẽ làm 1 công việc khá đơn giản là viết thêm 1 phương thức Update dữ liệu nữa rồi gọi theo mỗi lần gọi phương thức Show().
Ví dụ : frm1 mình có 1 GridView, cần được làm mới mỗi khi frm1 hiện.
Trong class frm1 mình viêt:
public void CapNhatDuLieu()
{
// GetData() là 1 phương thức cập nhật lại dữ liệu
GridView.DataSource = GetData();
}
=> Mỗi lần Show Form 1 hãy kèm thêm 1 lệnh cập nhật
Winform.FORM1.CapNhatDuLieu();
Winform.FORM1.Show();
Vậy là xong rồi.... Có vẻ hơi dài dòng nhỉ ^^!
Nếu làm theo cách này, chương trình của bạn dù nặng đến đâu thì cũng chỉ khác nhau ở thời gian Load thôi, chứ chạy thì mượt thôi rồi :))
Thêm nút lên GridView của DevExpress bằng HyperLinkEdit
thuvienwinform - Với gridView của DevExpress, nếu không nói quá thì có thể hiển thị dữ liệu với mọi cách mà ta muốn. Nó hỗ trợ quá tuyệt vời! Nhưng thêm những thứ khác ngoài dữ liệu. Cụ thể như nút, ô lựa chọn,...ta làm thế nào! Sau đây mình xin được giới thiệu cách thêm nút lên gridView của DevExpress. Cách là là thêm một cột HyperLinkEdit cho GridView sau đó hiển thị HyperLink đó bằng hình ảnh (nhìn giống nút)
CÁC BƯỚC THỰC HIỆN (3 BƯỚC)
Ấn mũi tên chọn Add Column
Bước 2: Chỉnh Column Edit cho cột vừa thêm. Chọn New -> HyperLinkEdit
Ấn mũi tên của cột xong sủa giá tị của Column Edit thành HyperLinkEdit
Bước 3: Đặt ảnh cho HyperLinkEdit
Ấn mũi tên chọn Run Designer
Columns -> chọn cột vừa thêm. Chú ý tên biến ở đây là repositoryItemHyperLinkEdit1
Kéo xuống đến thuộc tính Image Chọn hình ảnh cẩn hiển thị
Căn giữa cho ảnh (mục đích là che đi chữ của cột)
Bước 4: Viết mã cho sự kiện ấn (Click) cho nó. Chúng nó sẽ viết nó trong sự kiện Form_Load:
Cách 1:
private void frmQuanLiBaiSoan_Load(object sender, EventArgs e) { repositoryItemHyperLinkEdit1.Click += repositoryItemHyperLinkEdit1_Click;//Gõ += xong ấn Tab } private void repositoryItemHyperLinkEdit1_Click(object sender, EventArgs e) { //mã sự kiện }
Cách 2:
private void frmQuanLiBaiSoan_Load(object sender, EventArgs e) { repositoryItemHyperLinkEdit1.Click += (s1, e1) => { //mã sự kiện }; }
Tham khảo thêm việc tùy chình GridView tại http://nvnhan2910.blogspot.com/2014/06/windowform-lam-viec-voi-gridview-grid.html
Xem thêm:
Phân trang trong winform | Paging in winform
thuvienwinform - Phân trang thực ra là một đặc trưng trong lập trình web. Chia dữ liệu cần tải (load) ra làm nhiều phần nhỏ giúp việc hiển thị nhanh hơn (do dữ liệu tải về nhỏ hơn). Trong winform thì phân trang giúp cho sử dụng tài nguyên (cụ thể là RAM) ít hơn. Nhưng mình thử thì không giảm đi là bao :)), có lẽ do mình chưa giải phòng bộ nhớ tốt.
Sau đây mình xin giới thiệu với các bạn phân trang trong winform đằng LINQToSQL
Thư viện phân trang: https://www.dropbox.com/s/nj6fnuso2b2138p/ThuVienWinform.PhanTrang.dll (14KB)
Chương trình mẫu: https://www.dropbox.com/s/z9dvnbtceu3xv40/ThuVienWinform-PhanTrangLINQ.rar (710KB)
Nếu không tải được trên DropBox các bạn liên hệ trực tiếp thuvienwinform@gmail.com để mình gửi hoặc chạy Ultrasuft để truy cập lại DropBox
Trong chương trình mẫu có 2 tệp tin chứa cơ sở dữ liệu cho nó chạy các bạn nạp nó vào rồi sửa lại kết nối cho LINQ mới chạy được
Giới thiệu ThuVienWinform.PhanTrang:
- Với thư viện này sẽ không làm ảnh hưởng đến mã đã viết vì không cần thêm dòng code nào cả, chỉ việc khai báo và xài thui
- Khai báo:
phanTrang = new PhanTrangTruyenThong<tbPhanTrang>(this.db, this.bindingNavigator1, 20);Hoặc
PhanTrangTuyChinh<tbPhanTrang> pTrang = new PhanTrangTuyChinh<tbPhanTrang>(this.db, button1, comboBox1, button2, bindingNavigator1.BindingSource, 20);Trong đó:
+ tbPhanTrang là đối tượng cần phân trang, ở đây là một bảng tbPhanTrang trong CSDL
+ db là biến DataContext của LINQToSQL
+ bindingNavigator1: thanh điều hướng cho datagridView
+ 20: số hàng trên 1 trang
+ button1: là nút nhảy về trang sau
+ button2: là nút nhảy về trang trước
+ comboBox1: là comboBox để hiển thị các trang
+ bindingNagigator1.BindingSource là BindingSource của datagridView
- Chế độ:
+ PhanTrangTruyenThong: phân trang dựa vào bindingNavigator có sẵn, mình sẽ thêm 2 nút tiến lùi và 2 cái comboBox để hiển thị số trang lên đó
+ PhanTrangTuyChinh: truyền vào 2 nút và 1 comboBox có sẵn để làm 2 nút tiến lùi và hiển thị danh sách trang.
- Thuộc tính và sự kiện:
+ TrangHienTai: lấy về hoặc đặt trang hiện tại (set, get)
+ sự kiện NhayTrang: trả về hướng nhảy (tiến hoặc lùi) và số trang nhảy
- Mã phân trang bằng LINQ
/// <summary> /// Lấy dữ liệu từ chiSoDau đến chiSoCuoi /// </summary> /// <typeparam name="doiTuongCanPhanTrang">Đối tượng cần phân trang</typeparam> /// <param name="db">DataContext chứa dữ liệu cần phân trang</param> /// <param name="chiSoDau">Chỉ số đầu</param> /// <param name="chiSoCuoi">Chỉ số cuối</param> /// <returns></returns> public object DuLieuPhanTrang<doiTuongCanPhanTrang>(DataContext db, int chiSoDau, int chiSoCuoi) where doiTuongCanPhanTrang : class { try { var phanTrangs = (from p in db.GetTable<doiTuongCanPhanTrang>() select p).Skip(chiSoDau).Take(chiSoCuoi - chiSoDau); return phanTrangs; } catch { return null; } }
- Tư tưởng phân trang theo mình hiểu như sau: có một kho dữ liệu lớn (ví dụ 10 tỷ trường), ta không tải hết 10 tỷ trường đấy về để hiển thị lên dataGridView được (cháy máy mà chết mất). Nên phải chia nhỏ ra mỗi lần hiển thị 10 nghìn cái thôi!
- Có lỗi về thư viện hoặc ý tưởng mới về phân trang cùng nhau chia sẻ các bạn nha
- Chia sẻ mã ThuVienWinform.PhanTrang.dll quan hòm thư thuvienwinform@gmail.com nha!
Hiển thị một đối tượng lên DatagridView
thuvienwinform - Có rất nhiều trường hợp ta cần hiển thị đối tượng lên bảng để hiển thị đẹp hơn cũng như dễ dàng trong việc nhập, xử lí dữ liệu. Tương tự cách làm với LINQ thì ra chỉ cần thêm đối tượng của minh vào Data Sources rồi kéo ra dataGridview là xong (đơn giản nhất) hoặc viết mã hiển thị đối tượng đó lên bảng cũng được (nhưng công việc thiết kế như đặt tên cột, thứ tự cột, ... sẽ khó khăn hơn). Mình sẽ giới thiệu cả 2 cách
Mẫu: https://www.dropbox.com/s/9tdv0s2f5bmnxsr/thuvienwinform-HienThiDoiTuongLenDgv.rar (55KB)
Cách 1: Thêm đối tượng và Data Sources rồi kéo thả ra bảng (đơn giản nhất)
- cách này nhanh, tùy biến, thêm, xóa thuộc tính của đối tượng và thiết kế dễ dàng (nên dùng cách này)
B1: Khai báo đối tượng:
- Đối tượng Class1 với các thuộc tính của nó
class Class1 { public string ThuocTinh1 { set; get; } public string ThuocTinh2 { set; get; } public string ThuocTinh3 { set; get; } public string ThuocTinh4 { set; get; } public string ThuocTinh5 { set; get; } public string ThuocTinh6 { set; get; } }
B2: Thêm nó vào Data Sources
B3: Đối tượng này ra form (phải ở chế độ thiết kế (Design))
Chọn DataGridView
Kéo ra
DataSource tự sinh
B4: thêm dữ liệu
- Chỉ cẩn thêm và data source là nó sẽ tự hiện lên bảng:
//Khai báo và truyền giá trị cho các thuộc tính của dối tượng Class1 doiTuong = new Class1(); doiTuong.ThuocTinh1 = "1"; doiTuong.ThuocTinh2 = "2"; doiTuong.ThuocTinh3 = "3"; doiTuong.ThuocTinh4 = "4"; doiTuong.ThuocTinh5 = "5"; doiTuong.ThuocTinh6 = "6"; class1BindingSource.Add(doiTuong);//Thêm đối tượng này vào bảng
Kết quả:
- Để tùy biến giao diện ấn vào mũi tên nhỏ -> Edit Columns
Cách 2: Viết mã để hiển thị:
- Cách này khi thêm một thuộc tính cho đối tượng sẽ khó khăn trong việc sửa mã.
B1: cũng khai báo đối tượng như ở Cách 1
B2: Kéo một dataGridView ra form
B3: Viết mã nạp đối tượng lên bảng
//Dùng code BindingSource dts = new BindingSource();//Khai báo BindingSource dts.DataSource = typeof(Class1);// => datasource này chỉ thêm được những đối tượng Class1. Nếu không thì nó sẽ nhận typeof(đối tượng đầu tiên thêm vào) dataGridView1.DataSource = dts; dts.Add(doiTuong);//Thêm 1 đối tượng lên bảng (sẽ tự tạo ra 1 hàng mới). Biến doiTuong giống như ở cách 1 dts.AddNew();//Thêm 1 hàng mới (các giá trị đều rỗng) //Đặt tên cho các cột dataGridView1.Columns["ThuocTinh1"].HeaderText = "cột 1"; dataGridView1.Columns["ThuocTinh2"].HeaderText = "cột 2"; for (int i = 3; i <= 6; i++) dataGridView1.Columns["ThuocTinh" + i].HeaderText = "cột " + i; //Sắp xếp vị trí cho cột dataGridView1.Columns["ThuocTinh2"].DisplayIndex = 0;
Kết quả:
Lấy, sửa dữ liệu đã được thêm vào:
//Lấy dữ liệu string dt1 = ((Class1)class1BindingSource.Current).ThuocTinh1; string dt2 = ((Class1)class1BindingSource.Current).ThuocTinh2; //Sửa ((Class1)class1BindingSource.Current).ThuocTinh2 = "sửa"; foreach (Class1 thuocTinh in class1BindingSource) thuocTinh.ThuocTinh1 = "OK";
Sự kiện thay đổi nội dung tệp tin. Event change file
thuvienwinform - Chắc hẳn các bạn rất hay gặp phải thông báo này nếu dùng 2 chương trình cùng chỉnh sửa nội dung 1 tệp tin. Để bắt được sự kiện tệp tin bị thay đổi nội dung, được tạo mới hoặc bị xóa đi ta dùng FileSystemWatcher tron System.IO.
Project demo: https://www.dropbox.com/s/vv25p45gmdkat2s/thuvienwinform-FileSystemWatcher%28Kiem%20tra%20su%20thay%20doi%20cua%20file%29.rar (49KB)
private void KiemTraSuThayDoiCuaFile(string thuMuc, string tenFile) { FileSystemWatcher fwc = new FileSystemWatcher(); fwc.Path = thuMuc; fwc.Filter = tenFile; fwc.NotifyFilter = NotifyFilters.LastWrite; fwc.EnableRaisingEvents = true; fwc.Changed += (s1, e1) => { //code cần thực hiện khi file thay đổi MessageBox.Show("File da bi thay doi"); }; }
Bắt sự kiện bật, tắt chương trình. Event start, stop process
thuvienwinform - C# hỗ trợ người lập trình biết được chương trình nào vừa được bắt đầu, chương trình nào vừa kết thúc thông qua sự kiện EventArrivedEventHandler của ManagementEventWatcher nằm trong bộ thư viện System.Management. Để bắt được các sự kiện này, đầu tiên chương trình phải có quyền admin. Để thực hiện gán quyền admin cho chương trình xem thêm tại: http://thuvienwinform.blogspot.com/2013/09/item-manifes-tchay-ung-dung-winform-voi-quyen-admin.html
Project demo: https://www.dropbox.com/s/es33d1d5413oqop/thuvienwinform-ManagermentEventWatcher%28KiemTraSuThayDoiCuaTaskMgr%29.rar
Sau khi thêm quyền admin cho chương trình, ta thoát visual ra và chạy lại nó với quyền admin
Chú ý: nếu không sử dụng được ManagementEventWatcher thì phải thực hiện Add reference System.Management bằng tay
Rồi, ok code như sau:
1. Bắt sự kiện chương trình mới được bật lên
void ChuongTrinhBat() { WqlEventQuery q = new WqlEventQuery("Win32_ProcessStartTrace"); ManagementEventWatcher w = new ManagementEventWatcher(q); w.EventArrived += new EventArrivedEventHandler(voidChuongTrinhBat); w.Start(); } private void voidChuongTrinhTat(object sender, EventArrivedEventArgs e) { string s = ""; foreach (var pd in e.NewEvent.Properties) if(pd.Value != null) if (pd.Name == "ProcessName")// ngoai ra con co ProcessID, TIME_CREATED s += pd.Value.ToString() + "\n"; MessageBox.Show("Co mot chuong trinh vua moi tat\n" + s); }
2. Bắt sự kiện chương trình bị tắt đi
void ChuongTrinhTat() { ManagementEventWatcher w1 = new ManagementEventWatcher("select ProcessName from Win32_ProcessStopTrace"); w1.EventArrived += new EventArrivedEventHandler(voidChuongTrinhTat); w1.Start(); } private void voidChuongTrinhBat(object sender, EventArrivedEventArgs e) { string s = ""; foreach (var pd in e.NewEvent.Properties) if (pd.Value != null) if (pd.Name == "ProcessName")// ngoai ra con co ProcessID, TIME_CREATED s += pd.Value.ToString() + "\n"; MessageBox.Show("Co mot chuong trinh vua moi bat\n" + s); }
- Ngoài ra có thể chỉnh lại cái đoạn select một chút để lấy những giá trị cần thiết như:
+ Lấy ProcessName: select ProcessName from Win32_ProcessStopTrace
+ Lấy thời gian: select TIME_CREATE from Win32_ProcessStartTrace
+...
[CODE] Truyền dữ liệu qua lại giữa các Process và ứng dụng
thuvienwinform - Xin chào ! Hôm nay mình sẽ hướng dẫn truyền dữ liệu qua lại giữa các Process. Việc này tưởng như không quan trọng lắm nhưng thực ra nó rất cần thiết khi code các phần mềm liên quan tới quản lí máy tính như Antivirus....
I. Vấn đề
Chắc hẳn các bạn đã dùng nhiều phần mềm diệt virus và thấy luôn có 1 exe riêng cho Tray (chạy dưới khay taskbar). Hãy tự hỏi tại sao lại phải tách riêng ra như vậy mà không code gộp vào 1 exe cho dễ quản lí ???
Đơn giản thôi, vì cái Tray đó làm nhiệm vụ quản lí Runtime (thời gian thực -- chạy liên tục cùng máy tính) và nếu gộp vào thì sẽ rất ngốn RAM (Ram sẽ phải load cả phần giao diện ...) nên để hệ thống chạy "êm và không nặng nề" người ta đã làm Tray ra 1 exe riêng biệt . ^^ và bây giờ việc truyền dữ liệu giữa Process là vấn đề quan trọng
II. Giải quyết
Thời còn .NET Framework 3.0 trở xuống người ta vẫn phải truyền dữ liệu qua lại giữa Process thông qua File. Nhưng tới .NET 3.5 , đã có 1 công nghệ xuất hiện để giải quyết vấn đề này.
Hôm nay mình sẽ giới thiệu vs các bạn công nghệ Pipes - công nghệ này chạy theo mô hình Server/Client
(using System.IO.Pipes) tức là 1 process sẽ đóng vai trò như 1 máy chủ, các process khác gửi nhận dữ liệu thông qua Server.
Xem 1 ví dụ đơn giản nhé (Ví dụ vẫn là cách học dễ nhất nhỉ ^^)
* Server :
Form server của mình có 1 textbox và 1 nút
(ấn vào button sẽ gửi data trong textbox cho Client)
Form Client chỉ có 1 ricktexbox để cập nhật
Chạy server trước, sau đó chạy client và thử nhé ^^!
Ô xong rồi ^^!
Vậy đã truyền được dữ liệu giữa các process ^^
I. Vấn đề
Chắc hẳn các bạn đã dùng nhiều phần mềm diệt virus và thấy luôn có 1 exe riêng cho Tray (chạy dưới khay taskbar). Hãy tự hỏi tại sao lại phải tách riêng ra như vậy mà không code gộp vào 1 exe cho dễ quản lí ???
Đơn giản thôi, vì cái Tray đó làm nhiệm vụ quản lí Runtime (thời gian thực -- chạy liên tục cùng máy tính) và nếu gộp vào thì sẽ rất ngốn RAM (Ram sẽ phải load cả phần giao diện ...) nên để hệ thống chạy "êm và không nặng nề" người ta đã làm Tray ra 1 exe riêng biệt . ^^ và bây giờ việc truyền dữ liệu giữa Process là vấn đề quan trọng
II. Giải quyết
Thời còn .NET Framework 3.0 trở xuống người ta vẫn phải truyền dữ liệu qua lại giữa Process thông qua File. Nhưng tới .NET 3.5 , đã có 1 công nghệ xuất hiện để giải quyết vấn đề này.
Hôm nay mình sẽ giới thiệu vs các bạn công nghệ Pipes - công nghệ này chạy theo mô hình Server/Client
(using System.IO.Pipes) tức là 1 process sẽ đóng vai trò như 1 máy chủ, các process khác gửi nhận dữ liệu thông qua Server.
Xem 1 ví dụ đơn giản nhé (Ví dụ vẫn là cách học dễ nhất nhỉ ^^)
* Server :
Form server của mình có 1 textbox và 1 nút
(ấn vào button sẽ gửi data trong textbox cho Client)
// Biến Server private NamedPipeServerStream sv; public Server() { InitializeComponent(); } private void Server_Load(object sender, EventArgs e) { // Tạo server có tên "ServerTest" sv = new NamedPipeServerStream("ServerTest", PipeDirection.InOut); // Đợi 1 client khác kết nối sv.WaitForConnection(); } private void button1_Click(object sender, EventArgs e) { // Khi ấn Button1 - Gửi dữ liệu cho client (phải gửi dạng byte nhé) var data = Encoding.Unicode.GetBytes(this.textBox1.Text); sv.Write(data, 0, data.Length); }
* Client
Form Client chỉ có 1 ricktexbox để cập nhật
// Client NamedPipeClientStream stream; public Client() { InitializeComponent(); } private void Client_Load(object sender, EventArgs e) { // Kết nối tới "ServerTest" stream = new NamedPipeClientStream("ServerTest"); stream.Connect(); } private void timer1_Tick(object sender, EventArgs e) { // Timer này cập nhật dữ liệu liên tục dưa vào RickTextbox mình đã tạo var re = new byte[1000]; stream.Read(re, 0, 1000); string data = Encoding.Unicode.GetString(re); if (data != "") richTextBox1.Text += "\n" + data; }
Chạy server trước, sau đó chạy client và thử nhé ^^!
Ô xong rồi ^^!
Vậy đã truyền được dữ liệu giữa các process ^^
[Code] Xử lí sự kiện cho nhiều Control
thuvienwinform - Chào ! Khi tạo form chắc hẳn bạn sẽ gặp rất nhiều control mà sẽ dùng chung một sự kiện. Nhất là đối với các hiệu ứng cho các control (Ví dụ như sự kiện MouseMove và MouseLeave...)
Hôm nay chúng ta sẽ giải quyết vấn đề này. Cũng dễ thôi ^^
I. VẤN ĐỀ
Đối với một Form có rất nhiều Control ... và bạn muốn Form "Lung linh" hơn thì cần thêm hiệu ứng cho các Control trong Form. Ví dụ như khi trỏ chuột vào Lable thì chữ nó đậm lên - khi ngừng trỏ thì quay lại như ban đầu. >> Bình thường bạn phải tạo từng sự kiện cho từng Lable (mỗi Lable 2 sự kiện lận đó .. điều này tương đương với 2 procedure nhỏ) Mà ví dụ như có 100 Label thì sao nhỉ --> 200 sự kiện OMG ... Đủ chết rồi đấy ^^
II. GIẢI QUYẾT
Đơn giản thôi, ở đây chúng ta sẽ tạo ra một lớp có đầy đủ các sự kiện ... và sau đó chỉ cần truyền Control vào lớp này là xong ^^! Bắt đầu nhé : Ở đây mình sẽ tạo lớp XULIHIEUUNG như sau :
Bây giờ thử mở Form ra coi... Khi bạn trỏ chuột vào button1 và khi di chuyển chuột ra khỏi chỗ đó .. Xem thế nào :)) (1 dòng này = 6 dòng code tay đấy, chưa kể phải mở Properties của từng Control mà chọn sự kiện)
OK, vậy là xong rồi. Đơn giản đúng không :D
I. VẤN ĐỀ
Đối với một Form có rất nhiều Control ... và bạn muốn Form "Lung linh" hơn thì cần thêm hiệu ứng cho các Control trong Form. Ví dụ như khi trỏ chuột vào Lable thì chữ nó đậm lên - khi ngừng trỏ thì quay lại như ban đầu. >> Bình thường bạn phải tạo từng sự kiện cho từng Lable (mỗi Lable 2 sự kiện lận đó .. điều này tương đương với 2 procedure nhỏ) Mà ví dụ như có 100 Label thì sao nhỉ --> 200 sự kiện OMG ... Đủ chết rồi đấy ^^
II. GIẢI QUYẾT
Đơn giản thôi, ở đây chúng ta sẽ tạo ra một lớp có đầy đủ các sự kiện ... và sau đó chỉ cần truyền Control vào lớp này là xong ^^! Bắt đầu nhé : Ở đây mình sẽ tạo lớp XULIHIEUUNG như sau :
public class XULIHIEUUNG { Control g_Control; public void TAOHIEUUNG(Control c) { g_Control = c; btn.MouseMove += new System.Windows.Forms.MouseEventHandler(MouseMoveEvent); btn.MouseLeave += new System.EventHandler(MouseLeaveEvent); } public void MouseMoveEvent(object sender, EventArgs e) { g_Control.Text = "Ô bắt được con chuột"; } public void MouseLeaveEvent(object sender, EventArgs e) { g_Control.Text = "Chuột chạy mất rồi"; } }
Trong hàm khởi tạo form chỉ cần thêm code sau bạn chỉ cần thêm code sau đây :
new XULIHIEUUNG().TAOHIEUUNG(button1);
Bây giờ thử mở Form ra coi... Khi bạn trỏ chuột vào button1 và khi di chuyển chuột ra khỏi chỗ đó .. Xem thế nào :)) (1 dòng này = 6 dòng code tay đấy, chưa kể phải mở Properties của từng Control mà chọn sự kiện)
OK, vậy là xong rồi. Đơn giản đúng không :D
Thêm thuộc tính, sự kiện cho các điểu khiển trong winform
thuvienwinform - Apply Attributes in Windows Forms Controls (áp dụng các thuộc tính vào các điều khiển trong winform) sẽ giúp chúng ta thêm những sự kiện, thuộc tính chúng ta cần vào các control này. Ví dụ như thêm tính năng chuẩn hóa cho textBox, hoặc giới hạn độ dài cho textBox. Rất tiện trong quá trình code và sau này, tức là dùng cho được nhiều sản phẩm. Chính vì sự hữu ích này, hôm nay mình xin được chia sẻ cách thêm thuộc tính và sự kiện cho các điều khiển trong winform.
Tải về project demo: https://www.dropbox.com/s/6ih1d0oephk97r2/thuvienwinform-ThemThuocTinhChoControl.rar (46KB)
Bài viết này sẽ giới thiệu việc thêm tính năng chuẩn hóa và giới hạn độ dài cho TextBox. Gồm 2 phần
- Phần I: Thêm thuộc tính, sự kiện cho 1 điều khiển dựa trên lớp kế thừa
- Phần II: Tạo 1 điều khiển chứa nhiều điều khiển (từ các điều khiển đã có)
Chú ý: nếu tải về mở ra lỗi thì ấn F5 cho nó chạy sẽ hết lỗi (Do nó chưa nạp các điều khiển tự tạo vào)
- Để đọc code dễ ấn chuột phải vào code -> Outlining -> Collapse to Definitions (Ctrl + M,O).
- Để xem code của cotrol không có Design: ấn F7 hoặc ấn vào Switch to code...
I. Thêm thuộc tính, sự kiện cho 1 điều khiển
1. Thêm thuộc tính
- Rất đơn giản thôi. Đầu tiên thêm 1 class với tên: MyTextBox
- Sau đó ta thêm các thuộc tính cho MyTextBox như sau:
[Category("Thuộc tính xây dựng thêm")] [Description("Chuẩn hóa văn bản nhập vào. Viết hoa kí tự sau dấu cách")] [DefaultValue(true)] public bool ChuanHoa { get; set; } private DoDai _doDai;//Cái này phục vụ cho việc thêm sự kiện sau này [Category("Thuộc tính xây dựng thêm")] [Description("Định độ dài cho văn bản \nNgắn: 30 kí tự\nBình thường: 60 kí tự\nDài:255 kí tự")] public DoDai ĐộDài { get { return _doDai; } set{_doDai = value;} }
Với DoDai là 1 enum
public enum DoDai { Ngắn, BìnhThường, Dài, TốiĐa }
Trở lại phần thiết kế ta đã có được như này
2. Xây dựng chức năng chuẩn hóa, giới hạn độ dài
a. Chuẩn hóa- Chúng ta sẽ chuẩn hóa sau khi nhập chữ vào MyTextBox xong. Sử dụng sự kiện LostFocus và ấn nút Enter để thực hiện chuẩn hóa. this.Text = ChuanHoaXau(this.Text);
protected override void OnLostFocus(EventArgs e) { base.OnLostFocus(e); ThucHienChuanHoa(); } protected override void OnKeyDown(System.Windows.Forms.KeyEventArgs e) { base.OnKeyDown(e); //Ấn enter if (e.KeyCode == System.Windows.Forms.Keys.Enter) ThucHienChuanHoa(); } private void ThucHienChuanHoa() { //Chuẩn hóa xâu trong textBox this.Text = ChuanHoaXau(this.Text);//Các hàm còn lại xem trong project demo nha //Đưa con trỏ nhấp nháy về cuối dòng this.Select(this.Text.Length, this.Text.Length); }
Kết quả:
b. Giới hạn độ dài
- Để giới hạn độ dài ta sử dụng sự kiện TextChanged
protected override void OnTextChanged(EventArgs e) { base.OnTextChanged(e); int doDaiToiDa = 0; switch (ĐộDài) { case DoDai.Ngắn : doDaiToiDa = 30; break; case DoDai.BìnhThường : doDaiToiDa = 60; break; case DoDai.Dài : doDaiToiDa = 255; break; default: break; }; if (ĐộDài != DoDai.TốiĐa) if (this.Text.Length > doDaiToiDa) ThietLapDoDai(doDaiToiDa); } /// <summary> /// Thiết lập độ dài kí tự trong textBox /// </summary> /// <param name="ddtd">Độ dài tối đa cho phép</param> private void ThietLapDoDai(int ddtd) { //Dữ lại đoạn văn bản cho phép this.Text = this.Text.Substring(0, ddtd); //Đưa con trỏ nhấp nháy về cuối dòng this.Select(ddtd, ddtd); }
- Cách này khá thủ công như có lẽ như vậy sẽ dễ hiểu hơn. Để tối ưu thì ta sửa luôn việc set get biến Text của TextBox. Chuẩn hóa luôn khi set get
3. Bắt sự kiện thay đổi giá trị ĐộDài
a. Sử dụng delegate EventHandler- Tạo sự kiện
public event EventHandler ThayDoiDoDai;//Khai báo sự kiện
- Code cho sự kiện
protected virtual void OnThayDoiDoDai() { EventHandler handler = this.ThayDoiDoDai; if (handler != null) { handler(this, EventArgs.Empty); } }
- OK. Đã có sự kiện! Bây giờ đặt vào chỗ cần thực hiện sự kiện. Đó là khi giá trị ĐộDài thay đổi. Là lúc nào nhỉ?? Chính là lúc set get giá trị cho nó
public DoDai ĐộDài { get { return _doDai; } set { _doDai = value; //Mỗi khi thay đổi giá trị -> set, get 1 lần => chính là sự kiện thay đổi giá trị OnThayDoiDoDai(); } }
b. Tạo lớp kế thừa của EventHandler để tạo thêm các giá trị cho sự kiện
- Ví như sự kiện CellClick của DataGridView có thể lấy giá trị hàng (e.RowIndex). Vậy làm như thế nào để thêm các thuộc tính cho sự kiện. Ta cần tạo 1 lớp kế thừa của thằng EventHandler như sau:
//Tạo class bằng file mới hoặc trong cùng class MyTextBox đều được. Xem thêm trong project demo public class ThayDoiGiaTriDoDai : EventArgs { public DoDai GiaTriDoDai { get; set; } public bool DuocChuanHoa { get; set; } public string ThongTinChoSuKien { get { return "Sự kiện thay đổi giá trị độ dài của MyTextBox"; } } }
- Thêm sự kiện sử dụng lớp kế thừa này
[Category("Sự kiện Xây dựng thêm")] [Description("Bắt sự kiện thay đổi độ dài. Dùng class kế thừa")] public event EventHandler<ThayDoiGiaTriDoDai> ThayDoiDoDaiDungClass;//Khai báo sự kiện /// <summary> /// Code cho sự kiện /// </summary> /// <param name="s">Nạp giá trị đầu vào để hiển thị ra khi sử dụng sự kiện</param> protected virtual void OnThayDoiDoDai(ThayDoiGiaTriDoDai s) { EventHandler<ThayDoiGiaTriDoDai> handler = this.ThayDoiDoDaiDungClass; if (handler != null) { handler(this, s); } }
- OK bây giờ sửa lại lúc set get là được
public DoDai ĐộDài { get { return _doDai; } set { _doDai = value; //Mỗi khi thay đổi giá trị -> set, get 1 lần => chính là sự kiện thay đổi giá trị SuKien = new ThemThuocTinhChoControl.ThayDoiGiaTriDoDai(); SuKien.GiaTriDoDai = this.ĐộDài; SuKien.DuocChuanHoa = this.ChuanHoa; OnThayDoiDoDai(SuKien); } }
- Kết quả:
II. Tạo UserControl từ các control khác
- Trong thực tế có nhiều form ta có các kiểu bố trí giống nhau, có sự kết hợp của nhiều control giống nhau. Ví dụ như tập hợp các textBox để nhập thông tin họ tên ngày sinh,...thì ta chỉ cần tạo 1 lần vào sử dụng cho các form khác nhau. Để thực hiện việc này ta làm như sau:- Tạo 1 UserControl
- Sau đó thì kéo các điều khiển khác vào
- Ok có thể nói là xong rùi nhưng ta muốn thêm các thuộc tính, sự kiện cho thằng này thì làm tương tự phần I là OK.
- Ví dụ thêm thuộc tính tự động Anchor:
public bool TuDongDanCachCacPhanTu { get { return _tuDongDanCachCacPhanTu; } set { _tuDongDanCachCacPhanTu = value; if (_tuDongDanCachCacPhanTu) { this.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;//This ở đây là UserCOntrol this.myTextBox1.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; this.myTextBox2.Anchor = AnchorStyles.Bottom | AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right; } else { this.Anchor = AnchorStyles.Top | AnchorStyles.Left; this.myTextBox1.Anchor = AnchorStyles.Top | AnchorStyles.Left; this.myTextBox2.Anchor = AnchorStyles.Top | AnchorStyles.Left; } } }
- Sau khi đã thêm tạo được các file cs chỉ cần thêm vào các project khác là ok.
Nếu thấy hữu ích hãy để lại bình luận hoặc ấn G+. Cảm ơn các bạn đã đọc bài viết