Archive for June 2014

Gửi dữ liệu qua mạng với ThuVienWinform.Mang.GuiDuLieuNoiBo

thuvienwinform - Hôm nay blog xin được giới thiệu thư viện truyền dữ liệu qua mạng nội bộ với những dòng lệnh đơn giản. Ứng dụng trong việc truyền tin qua mạng. Cụ thể với chương trình gửi tin nhắn (chat) chỉ cần 10 dòng lệnh là xong! Hoặc có thể xây dựng thông báo, tương tác qua mạng. Thư viện này thiết kế theo mô hình chủ - khách. Máy chủ sẽ là trạm chung chuyển dữ liệu đến các máy khách.

Thư viện: https://www.dropbox.com/s/14s4s95v3k9z1m2/ThuVienWinform.Mang.GuiDuLieuNoiBo.rar (12KB)

Chương ứng dụng mẫu: https://www.dropbox.com/s/at4os8ddwusl3w0/ThuVienWinform-GuiDuLieuNoiBo.rar (185KB)

I. GIỚI THIỆU

Ứng dụng của nó có thể tạo ra những thông báo, kiểu như thông báo của facebook vậy, mình nghĩ là rất hữu ích với những chương trình trong mạng nội bộ, khi có một ai đó thêm dữ liệu -> hiện thông báo trên các máy khác (y) (y)

1. ThuVienWinform.Mang.GuiDuLieuNoiBo
- Là lớp nền, nó như bưu điện vậy, nhận vào các phong bì từ máy khách và gửi lại nó cho các khách khác
- Gồm:
+ PhongBiLAN: (phong bì :D) lớp chứa dữ liệu truyền đi. Dữ liệu được chứa trong NoiDung (PhongBiLAN.NoiDung).

2. ThuVienWinform.Mang.GuiDuLieuNoiBo.MayChu
- Nhiệm vụ duy nhất của nó là đọc tệp cài đặt xml và tạo ra một kênh http giao tiếp với các máy khách MayChuLAN.BatDau();

3. ThuVienWinform.Mang.GuiDuLieuNoiBo.MayKhach
- Chứa lớp MayKhach, thực hiện kết nối, gửi, nhận dữ liệu với máy chủ
- Lớp MayKhach gồm:
+ Thủ tục KetNoiMayChu(): thực hiện kết nối má chủ dựa trên các cài đặt trong tệp xml
+ Thủ tục GuiDuLieu(PhongBiLAN): gửi một gói dữ liệu đến máy chủ (sau đó máy chủ xử lí và gửi đến các máy khách)
- Sự kiện NhanDuLieu: thực hiện mỗi khi thực hiện thủ tục GuiDuLieu

4. Chú ý:
Vì phương pháp truyền sự kiện qua LAN mình dùng kiểu thực hiện sự kiện trên máy chủ xong truyền kết quả về cho máy khách nên sẽ xẩy ra xung đột trong sử dụng các điều khiển (controls). Vì vậy các điều khiển được sử dụng trong sự kiện NhanDuLieu cần phải xử lí nó bằng phương thức Invoke. Cái này là tiến trình trên máy khác nên rất tiếc CheckForIntellegalCrossThreadsCall = false; không có tác dụng

II. VÍ DỤ CHƯƠNG TRÌNH GỬI TIN

Chủ:
using ThuVienWinform.Mang.GuiDuLieuNoiBo;
using ThuVienWinform.Mang.GuiDuLieuNoiBo.MayChu;

Khách:
using ThuVienWinform.Mang.GuiDuLieuNoiBo;
using ThuVienWinform.Mang.GuiDuLieuNoiBo.MayKhach;

Trong chương trình ví dụ này đối tượng được gửi đi (gói trong phong bì) là TinNhan:
[Serializable]//Đối tượng muốn gửi đi phải đánh dấu Serializable
public class TinNhan
{
    public string NguoiGui { set; get; }
    public string NoiDung { set; get; }
}

1. Khởi tạo máy chủ:
ThuVienWinform.Mang.GuiDuLieuNoiBo.MayChu.MayChuLAN.BatDau();

2. Kết nối máy khách với máy chủ:
ThuVienWinform.Mang.GuiDuLieuNoiBo.MayKhach.MayKhach khach = new ThuVienWinform.Mang.GuiDuLieuNoiBo.MayKhach.MayKhach();

khach.KetNoiMayChu();

3. Gửi tin:
PhongBiLAN phongBi = new PhongBiLAN();//Tạo ra 1 cái phong bì

phongBi.NoiDung = doiTuongCanGui;//Đưa tin nhắn vào phong bì

khach.GuiDuLieu(phongBi);//Gửi dữ liệu đi

4. Nhận tin
khach.NhanDuLieu += (phogBi) =>
    {
        MessageBox.Show(phogBi.NoiDung);
    };

6/18/2014
Đăng bởi :
Nhãn :

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)

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!
6/17/2014
Đăng bở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 :
frmMain frm = new frmMain();
frm.Show()
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 .
Ư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 :))





6/15/2014
Đăng bởi :
Nhãn :

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)

Bước 1: Thêm 1 cột cho GridView

Ấ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!
6/13/2014
Đăng bởi :
Nhãn : ,

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";

6/03/2014
Đăng bởi :
Nhãn :

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");
    };
}


6/01/2014
Đăng bởi :
Nhãn :

Nhận ngay 100$ cho VPS

Mua hàng ủng hộ page

Ủng hộ page

Nhãn

Code (45) Team Foundation Server (17) Database (14) News (14) product (13) toolbox (10) Linq (9) SoftDesign (8) XNA (6) API (5) Project (5) item (4)

- Bản quyền thuộc về Thư Viện WinForm - Giao diện: Metrominimalist - Thiết kế: Johanes Djogan -