Thứ Sáu, 27 tháng 6, 2014

Ở các bài đăng trước mình đã giới thiệu tới các bạn khái niệm LINQ và cách làm việc với LINQ, đấy là một cách giao tiếp với cơ sở dữ liệu rất thuận tiện và nhanh chóng, dễ dàng cho lập trình viên. Một tính năng đặc biệt quan trọng của "LINQ to SQL" là cách giao tiếp với cơ sở dữ liệu thông qua các biến Context, hỗ trợ code dưới dạng lambda, đơn giản hóa mọi vấn đề, và quan trọng hơn đó là tính năng Binding dữ liệu - đều đã được giới thiệu trong các bài đăng trước.

Microsoft ADO.NET Entity Framework là một khuôn khổ đối tượng Object/ Bảng đồ quan hệ Relational Mapping (ORM) cho phép các nhà phát triển dể dàng làm việc với dữ liệu quan hệ như là các đối tượng domain-specific, loại bỏ đi sự khó khăn trong việc truy cập dữ liệu trước đây. Bằng cách sử dụng Entity Framework, truy vấn LINQ, thì việc lấy và thao tác dữ liệu như các đối tượng trở nên mạnh mẽ hơn. Entity Framework ORM cung cấp các dịch vụ như change tracking, idenity resolution, lazay loading, và truy vấn dữ liệu tập trung vào business logic của ứng dụng.
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL


Đơn giản có thể định nghĩa Entity Framework như sau: Entity Framework là một khung Object/Relational Mapping (O/RM). Nó là một kỹ thuật mới cung cấp cho các nhà phát triển ADO.NET một cơ chế tự động để truy cập và lưu trữ dữ liệu trong cơ sở dữ liệu và làm việc với các kết quả ngoài DataReader và DataSet.
Các bạn có thể đọc thêm về O/RM tại đây.

Việc tại sao lại nên dùng Entity Framework sẽ được lý giải trong phần phân biệt Entity với LINQ to SQL.

I. Entity Framework là gì? Các thành phần của Entity Framework

Entity Framework là một bộ ánh xạ đối tượng – quan hệ cho phép người lập trình .NET  làm việc với dữ liệu quan hệ qua các đối tượng (object) nó giúp lập trình viên không cần viết mã cho (hầu hết) những gì liên quan đến truy cập dữ liệu. 

Các thành phần trong Entity Framework:
Code là mã lệnh tạo thành các lớp đối tượng dữ liệu cho phép thao tác với dữ liệu.
Model là sơ đồ gồm các hộp mô tả các thực thể và các đường nối kết mô tả các quan hệ.
Database là cơ sở dữ liệu (có thể là SQL Server, Compact SQL Server, Local database, MySQL, Oracle,…)

Có 3 cách sử dụng Entity Framework: Code First, Models First, Database First.
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

- Database first: là phương pháp chỉ nên dùng khi ta đã có sẵn CSDL (không phải tạo), EF Wizard sẽ tạo Model và Code cho ta.
- Models first: nên dùng khi ta bắt đầu thiết kế CSDL từ đầu (từ chưa có gì). Ta sẽ thiết kế mô hình CSDL (Model) EF sẽ tự tạo code cho ta, sau đó nhờ EF Wizard tạo CSDL.
- Code first: nên dùng khi đã có mô hình CSDL, ta sẽ chỉ viết code từ đó tạo Database.

Dù cách nào thì cuối cùng cũng phải có Code để thao tác trong mã lệnh và Database để lưu trữ dữ liệu. Model chỉ là một thành phần trung gian.

Theo kinh nghiệm của nhiều lập trình viên đi trước, Code First là phương án mềm dẻo nhất (hơi mất công ngồi gõ code, tuy nhiên nếu dùng tốt code snippets thì đỡ nhiều).

Trước đây khi lập trình CSDL trong VB, VC,… ta luôn tạo CSDL liệu trước, sau đó mới xây dựng mã lệnh truy cập dữ liệu.

Trong bài này tôi sẽ hướng dẫn tạo 1 project Code First với cơ sở dữ liệu có sẵn.

II. Bắt đầu làm việc với Entity Framework

Để làm việc với Entity Framework một cách hoàn chỉnh chúng ta phải cài thêm Entity Framework bản mới nhất từ NuGet:

B1. Tạo Project mới

B2. Cài EF Power Tools vào Visual Studio: Tools -> Library Paskage Manager -> Manage NuGet Packages for Solution…
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Bến trái, chọn Online. Nhập Entity Framework Power Tools vào khung Search (góc trên, bên phải) chọn Entity Framework Power Tools -> Install. 

Khi đã cài được, bạn chuột phải trên tên Project sẽ thấy có menu Entity Framework.

III. Tạo một ứng dụng Entity Code First sử dụng CSDL có sẵn

Code First tức là bạn phải code sau đó sinh Database từ code đó. Nhưng Database tạo ra như thế sẽ ít thuộc tính: ràng buộc, identity, unique... Giải pháp là tạo 1 database hoàn chỉnh trên SQL sau đó viết code để map CSDL với Entity của chúng ta.

Trước hết tạo ra các class mô tả các bảng trong CSDL của chúng ta, nó bao gồm các trường và thuộc tính, kiều của chúng.
public partial class tbLop
{
[Key]
[DatabaseGenerated(DatabaseGeneratedOption.None)]
public int IdLop { get; set; }

[StringLength(50)]
public string Lop { get; set; }
}
public partial class tbHocVien
{
[Key]
public int IdHocVien { get; set; }

public int? IdLop { get; set; }

[StringLength(50)]
public string HoTen { get; set; }

[Column(TypeName = "date")]
public DateTime? NgaySinh { get; set; }
}

Sau đó tạo 1 class Context - là class quản lý tất cả các bảng và giao tiếp với Entity, nó tương tự như class DataContext trong LINQ to SQL.
public partial class DataContext : DbContext
{
/// <summary>
/// Connection string lưu ở App.config
/// theo name="DataContext"
/// </summary>
public DataContext()
: base("name=DataContext")
{
}

public virtual DbSet<tbHocVien> tbHocViens { get; set; }
public virtual DbSet<tbLop> tbLops { get; set; }
}

Trong App.config ta thiết đặt ConnectionString để class Conext liên kết với CSDL đã có sẵn.
<connectionStrings>
<add name="DataContext" connectionString="data source=\SQLEXPRESS;initial catalog=db_EF;persist security info=True;MultipleActiveResultSets=True;App=EntityFramework" providerName="System.Data.SqlClient" />
</connectionStrings>


Cách này rất thủ công và dễ xảy ra sai sót. Để làm việc này chúng ta có thể cài thêm 1 tool của Visual Studio giúp ta tạo Code First từ Database một cách nhanh chóng, chính xác.
Các bạn download tool tại đây
Sau khi tải về và cài đặt, khởi động lại Visual Studio, tạo 1 Entity mới ta sẽ thấy rõ hơn.

Thêm 1 Entity Model, chọn "Code First from Database"
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Chọn Database có sẵn
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Nếu chưa có thì chọn New Connection

Chọn các bảng/view/store để add vào Model
Giới thiệu về Entity Framework - So sánh giữa Entity Framework với LINQ to SQL

Sau đó nó sẽ tự sinh ra các class như trên và ConnectionString được lưu trong App.config
Nếu chưa làm được có thể xem tại đây.

Sau khi khai báo các đối tượng của Entity ta có thể sử dụng nó tương tự như đối với LINQ to SQL. Hướng dẫn chi tiết các điểm khác nhau tôi sẽ viết trong 2 bài khác.

IV. So sánh giữa Entity Framework với LINQ to SQL

Sau một thời gian sử dụng Entity tôi rút ra được một số nhận định ban đầu như sau:

LINQ to SQL

- Chỉ làm việc với CSDL của SQL Server
- Tạo ra file .dbml
- Không hỗ trợ các kiểu phức tạp
- Không thể tạo CSDL từ đối tượng
- Chỉ có kiểu ánh xạ 1-1 giữa đối tượng class với table/views
- Sử dụng DataContext

Entity Framework

- Có thể làm việc với các CSDL: Oracle, DB2, MySQL, SQL Server...
- Tạo ra file .edmx, .csdl, .msl, .ssdl hoặc các file class .cs thông thường
- Hỗ trợ các kiểu phức tạp
- Có thể tạo CSDL từ Model/Code đã thiết kế
- Có thể ánh xạ 1-1, 1-nhiều, nhiều-1, nhiều-nhiều giữa đối tượng entity với table/view
- Sử dụng DbContext, Entity SQL, ObjectContext.

Và hơn nữa mô hình Code First sinh ra các class riêng biệt => có thể dễ dàng thay đổi khi thay đổi CSDL

Các câu hỏi thường gặp

1. Hỏi: Tại sao chúng ta cần "Entity Framework" trong khi chúng tôi đã có "LINQ 2 SQL" ?
Trả lời: "Entity Framework" không phải được thiết kế để cạnh tranh với "LINQ 2 SQL", xa hơn nó được thiết kế để nhằm phục vụ một mục đích lớn hơn. Nó là một giải pháp ORM hoàn chỉnh. LINQ Provider chỉ là một khía cạnh của "LINQ 2 SQL"...

2. Hỏi: Nếu "LINQ 2 SQL" không thực sự cần thiết tại sao nó vẫn tồn tại?
Trả lời: Bây giờ, tôi không thể chính thức trả lời câu hỏi này (tôi không là đại diện cho Microsoft) nếu bạn nhìn vào sự tiến hóa về các framework và những bản phát hành của họ thì có thể không có kết hợp lý nào khác hơn so với những trình bày ở đây

Microsoft, có lẽ chưa từng có ý định đưa "LINQ 2 SQL" như là một giải pháp hoặc một framework. Có lẽ Entity framework chưa thật sự sẵn sàng tại thời điểm mà .Net 3.5 xuất xưởng. Microsoft đã đưa "LINQ 2 SQL" ra như một giải pháp điểm dừng của cách biệt hoặc chỉ đơn thuần là một mẫu cho "LINQ provider". Họ cuối cùng đã đưa ra Entity Framework với. Net 3.5 SP1. Tôi thật sự cảm thấy Entity Framework đã trở thành một thành phần của bản phát hành chỉnh thức và không phải là một phần của một gói dịch vụ. Không thể có hai nghi ngờ rằng Entity Framework là cách đề nghị đầy tham vọng cho việc truy cập dữ liệu và LINQ.

3. Hỏi: Vậy có phải kết luận rằng chúng ta nên thay thế tất cả "LINQ 2 SQL" với "Entity Framework".
Trả lời: Điều này dường như có vẻ là một kết luận hợp lý và cần phải được thực hiện trong thời gian dài. Tuy nhiên, dường như bản phát hành hiện tại của Entity Framework là chưa thật sự sẵn sàng cho nhu cầu doanh nghiệp và có lẽ chúng ta cần phải chờ ở bản phát hành của Net 4.0. Một số thử nghiệm độc lập đã cố gắng để chứng minh "LINQ 2 SQL" trong thực hiện của Entity Framework. Tôi đã không thực hiện các thử nghiệm cho một trong hai xác nhận hay mâu thuẫn với việc nghiên cứu của họ, mà chỉ chờ đợi ở phiên bản .Net 4.0.
Xem thêm tại đây.

Nguồn tham khảo: tổng hợp từ Internet.

Thứ Ba, 24 tháng 6, 2014

"Timer" là một điều khiển khá hữu ích trong C# - Winform. Timer tương tự như "setInterval" hay "setTimeOut" trong JavaScript đều có chức năng thực hiện một số chức năng nhất định trong các khoảng thời gian lặp lại. Một đoạn chương trình sẽ được lặp đi lặp lại với khoảng nhất định mà không ảnh hưởng đến các tiến trình khác.
Có nhiều loại Timer: System.Windows.Forms.Timer, System.Timers.Timer, System.Threading.Timer. Nhưng để đơn giản bây giờ chúng ta sẽ sử dụng điều khiển Timer của Windows.Forms.
Sử dụng Timer và một số chức năng với Timer

Để khai báo 1 đối tượng Timer cách đơn giản là vào Toolbox tìm "Timer" rồi kéo vào form
Sử dụng Timer và một số chức năng với Timer

Đặt các thuộc tính cho Timer
Sử dụng Timer và một số chức năng với Timer

Trong đó Interval là khoảng thời gian sẽ lặp lại, đơn vị tính miliseconds. Ở ví dụ ta đã bật cho Timer chạy và đặt khoảng thời gian cho nó là 1 giây (1000 miliseconds).

Sự kiện duy nhất của Timer là Timer_Tick cho phép ta thay đổi sự kiện mỗi khi timer lặp lại thời gian. Tức là khi timer lặp lại thì code trong hàm Timer_Tick sẽ được thực hiện.

Bây giờ, tôi sẽ hướng dẫn một vài công dụng với Timer:

- Đồng hồ chạy số trong Window Form

Ta có 2 label để hiển thị thời gian và ngày tháng, 2 label sẽ được thay đổi nội dung sau từng giây. Vậy chúng ta cần 1 điều khiển timer với khoảng lặp là 1000, nội dung Timer_Tick tương tự như sau:
private void timer1_Tick(object sender, EventArgs e)
{
lblTime.Text = (DateTime.Now.Hour < 10 ? "0" + DateTime.Now.Hour.ToString() : DateTime.Now.Hour.ToString()) + ":" + (DateTime.Now.Minute < 10 ? "0" + DateTime.Now.Minute.ToString() : DateTime.Now.Minute.ToString()) + ":" + (DateTime.Now.Second < 10 ? "0" + DateTime.Now.Second.ToString() : DateTime.Now.Second.ToString());
lblDate.Text = DateTime.Now.DayOfWeek.ToString() + ", " + (DateTime.Now.Day < 10 ? "0" + DateTime.Now.Day.ToString() : DateTime.Now.Day.ToString()) + "/" + (DateTime.Now.Month < 10 ? "0" + DateTime.Now.Month.ToString() : DateTime.Now.Month.ToString()) + "/" + DateTime.Now.Year;
}

- Ảnh động trong Window Form

Ta đã biết ảnh động thực sự là tập hợp các ảnh tĩnh được hiển thị lần lượt, lặp đi lặp lại sau 1 khoảng thời gian nhất định. Và ở đây ta dùng Timer để đặt cái khoảng thời gian nhất định đó. Mỗi khi đến điểm Tick thì thay đổi ảnh ở trong PictureBox.
/// <summary>
/// Biến kiểm tra ảnh động
/// Không hiểu sao phải dùng thêm 1 biến ngoài để kiểm tra
/// </summary>
private int _img = 1;
private void timer1_Tick(object sender, EventArgs e)
{
if (_img == 1)
{
// Thay đổi ảnh
pictureBox1.Image = NhacViec.Properties.Resources.Alarm2;
_img = 2;
}
else
{
pictureBox1.Image = NhacViec.Properties.Resources.Alarm1;
_img = 1;
}
}


Demo về 2 ví dụ này có tại phần mềm Nhắc việc.
Nếu có hứng thú các bạn có thể xem thêm các phần Timer khác và sự khác nhau giữa chúng tại đây.

Thứ Bảy, 21 tháng 6, 2014

Bạn quá bận rộn trong công việc với máy tính hay bạn đang chìm đắm trong những trận đấu kinh điển, những trận combat không dứt ra được!?! Đôi khi bạn có việc gì đấy đã lên lịch từ trước nhưng rồi lại quên béng đi!? Bạn thỉnh thoảng có đặt báo thức ở máy điện thoại nhưng rồi cũng quên mất sự xuất hiện của nó vì lúc nào cũng dán mắt vào màn hình máy tính, thậm chí còn đeo tai nghe, "quên hết sự đời".

Rất đơn giản vì giờ đây đã có "Nhắc Việc" - phần mềm nhỏ gọn sẽ nhắc bạn, không bỏ lỡ những sự kiện quan trọng.
Nhắc việc - Phần mềm hữu ích cho những người bận rộn

Link download: tại đây.

- Tính năng

Thêm các tùy chọn: Tiêu đề, nhạc chuông, thời gian nhắc, lặp lại tương tự như báo thức ở điện thoại
Chạy tự động cùng window
Form nhắc việc ở trên "Top" để người dùng để ý
Chạy ẩn dưới khay hệ thống

- Thông tin

Phần mềm do mình tự tìm tòi + viết hoàn chỉnh
Dùng SQLite => Không được xóa các file trong thư mục cài đặt

- Nhược điểm

Tiêu tốn tài nguyên RAM khá lớn

Nhiều chương trình như UniKey, KasperSky, SkyDrive, DropBox... đều có 1 phần chương trình chạy ngầm trong hệ thống và có 1 biểu tượng icon nhỏ ở khay hệ thống - system tray. Bạn có 1 chương trình yêu cầu phải chạy liên tục và chạy ẩn (không hiện ở taskbar), có 1 biểu tượng ở khay hệ thống để người dùng có thể tương tác với chương trình. Rất đơn giản chúng ta sẽ sử dụng NotifyIcon cho việc này.
Sử dụng NotifyIcon - Cách ẩn chương trình xuống khay hệ thống

1. Sử dụng NotifyIcon

- Các bạn search ở ToolBox "NotifyIcon" và kéo vào trong form của mình.

- Các thuộc tính của NotifyIcon:
Sử dụng NotifyIcon - Cách ẩn chương trình xuống khay hệ thống

BaloonTipIcon, BaloonTipText, BaloonTipTitle hiện ra như 1 thông báo nhỏ ở khay hệ thống (nếu chúng ta cho hiện).
Sử dụng NotifyIcon - Cách ẩn chương trình xuống khay hệ thống

ContextMenuStrip là lựa chọn menu khi ấn chuột phải vào notifyIcon.
Text là phần hiện lên khi ta di chuột vào notifyIcon.
Đặt mặc định cho notifyIcon có Visible hay không!?

- Thiết lập các menu chuột phải cho NotifyIcon
Trong ToolBox ta tìm vào kéo 1 đối tượng ContextMenuStrip.
Thêm các MenuItem cho contextmenu đấy. Ở đây hỗ trợ nhiều loại như MenuItem (giống 1 button), ComboBox, TextBox, Separator (vạch ngăn cách).
Sử dụng NotifyIcon - Cách ẩn chương trình xuống khay hệ thống

Thêm sự kiện click cho các MenuItem này.

Để sử dụng ContextMenuStrip này cho NotifyIcon đừng quên thiết lập ở phần NotifyIcon như trên.

2. Ẩn chương trình xuống khay hệ thống

Việc này thực sự chỉ là ẩn chương trình đang chạy và cho hiện 1 cái NotifyIcon lên. NotifyIcon có các MenuItem để tương tác với chương trình đang chạy, như mở chương trình, thoát chương trình..., các chức năng do ta đặt ở phần ContextMenuStrip phía trên. Vì ẩn chương trình và chương trình luôn chạy ngầm nên ta phải tính làm sao để giảm thiểu tài nguyên sử dụng, form chúng ta cho chạy ngầm phải ít tốn tài nguyên, chỉ để thực hiện các chức năng cơ bản (như để gọi các form to hơn) hoặc chỉ là 1 service.

Để thực hiện ẩn chương trình ta thêm 1 button, hoặc gán vào các sự kiện khác (minimize form chẳng hạn)
Sự kiện click của button này như sau
private void btnExit_Click(object sender, EventArgs e)
{
// Cho hiện notifyIcon
notifyIcon1.Visible = true;
// Hiện BaloonTip hoặc không
notifyIcon1.ShowBalloonTip(10);

// Chọn ẩn
this.Hide();
// Hoặc
this.ShowInTaskbar = false;
WindowState = FormWindowState.Minimized;
// Hoặc cả 2 để ẩn form
}

Phần việc còn lại là do NotifyIcon phụ trách. Chẳng hạn ta muốn click chuột phải để hiện menu context, click chuột trái để mở form: Ta thêm 1 sự kiện Click hoặc MouseClick cho NotifyIcon
private void notifyIcon1_MouseClick(object sender, MouseEventArgs e)
{
if(e.Button == System.Windows.Forms.MouseButtons.Left)
{
// Ẩn notifyIcon đi
notifyIcon1.Visible = false;
// Cách này
WindowState = FormWindowState.Normal;
this.ShowInTaskbar = true;
// Hoặc
this.Show();
// Hoặc cả 2 miễn là phải tương ứng với lúc ẩn
}
}

Thứ Sáu, 20 tháng 6, 2014

Bạn thấy nhiều phần mềm có những form có hình dạng rất lạ (không phải hình chữ nhật, có border thông thường). Bạn hoàn toàn có thể tạo những form mang hình dạng đặc biệt tùy ý một cách đơn giản.
Customize Form - Tùy chỉnh form, tạo form có hình dạng bất kỳ
Như Photoshop chẳng hạn

Sau đây tôi sẽ hướng dẫn các bạn cách tạo 1 form tùy ý và các thao tác liên quan.

1. Tạo form với hình dạng tùy ý

Thực chất việc này là đặt 1 hình ảnh làm nền cho form rồi cho những phần còn lại "biến mất".
Customize Form - Tùy chỉnh form, tạo form có hình dạng bất kỳ

- Đầu tiên bạn thiết kế 1 cái hình ảnh làm nền cho form. Những phần không cần thiết thì bạn nên để trong suốt, rồi xuất ra ảnh .PNG

- Tiếp theo đặt "BackColor" của form là White, "BackgroundImage" là hình ảnh vừa tạo, FormBorderStyle None

- Đây là phần quan trọng nhất: Cuộn xuống chọn "TransparencyKey" là White => Nó sẽ tìm tất cả phần nào của background form màu trắng để làm trong suốt phần đó. 
Cách này vô cùng đơn giản, để có thể tạo được 1 form tùy ý. Chính vì thế mà nó có nhiều chỗ không trong suốt cho lắm, đặc biệt là những đường giao nhau giữa 2 màu, đoạn đường chéo... Những điểm này khá nhỏ vẫn có thể chấp nhận được. Nếu bạn muốn có nó một cách hoàn hảo + opacity của từng phần trong form thì phải dùng đến phần xử lý đồ họa.

2. Di chuyển cho form tùy chỉnh

Với 1 form đã tạo được như trên vấn đề là khi ta loại bỏ border của form thì làm sao để di chuyển form đây??? Chỉ còn cách code!!!  :)
Việc code còn đem lại cho ta những tùy chọn về di chuyển form do ta tự quyết định: chẳng hạn có cho form "chui ra phía ngoài màn hình" không hoặc là bị bó hẹp trong khuôn khổ của màn hình, cho phép người dùng click chuột ở đâu để di chuyển form???

Trong phần global ta khai báo các biến toàn cục như sau:
/// <summary>
/// Di chuyển form
/// </summary>
private bool drag = false;
private Point dragCursor, dragForm;

Quay lại phần thiết kế để double click và thêm 3 sự kiện: MouseDown, MouseMove, MouseUp cho form.
Chỉnh sửa các sự kiện đấy như sau:
private void Form1_MouseDown(object sender, MouseEventArgs e)
{
drag = true;
dragCursor = Cursor.Position;
dragForm = this.Location;
}

private void Form1_MouseMove(object sender, MouseEventArgs e)
{
int wid = SystemInformation.VirtualScreen.Width;
int hei = SystemInformation.VirtualScreen.Height;
if (drag)
{
// Phải using System.Drawing;
Point change = Point.Subtract(Cursor.Position, new Size(dragCursor));
Point newpos = Point.Add(dragForm, new Size(change));
// QUyết định có cho form chui ra ngoài màn hình không
if (newpos.X < 0) newpos.X = 0;
if (newpos.Y < 0) newpos.Y = 0;
if (newpos.X + this.Width > wid) newpos.X = wid - this.Width;
if (newpos.Y + this.Height > hei) newpos.Y = hei - this.Height;
this.Location = newpos;
}
}
private void Form1_MouseUp(object sender, MouseEventArgs e)
{
drag = false;
}

Như vậy hiện tại bạn có thể click vào bất cứ phần nào không trong suốt của form để di chuyển form.

3. Thêm một số phần khác

Khi loại bỏ border thì đồng nghĩa với việc không còn các nút Minimize, Maximize, Exit và box-shadow của form. Vậy ta phải thêm thủ công như sau

Thêm các nút điều khiển

Tự thiết kế hình ảnh cho các nút hoặc đơn giản chỉ là các button thông thường. Sau đó thêm sự kiện click như sau
private void btnMini_Click(object sender, EventArgs e)
{
this.WindowState = FormWindowState.Minimized;
}

private void btnExit_Click(object sender, EventArgs e)
{
Application.Exit();
}

Thêm box shadow cho form 

Chúng ta phải override 1 thủ tục của form như sau:
/// <summary>
/// Drop Shadow cho form
/// </summary>
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
// Bóng đổ
cp.ClassStyle |= 0x20000;
// Load các control cùng lúc
cp.ExStyle |= 0x02000000; // Turn on WS_EX_COMPOSITED
return cp;
}
}

Phần load các control 1 lúc có thể áp dụng cho các form khác, form có nhiều control. Chẳng hạn form bạn có rất nhiều control và thường xuyên phải Visible/Invisible chúng lần lượt. Như vậy khi các control hiện lên sẽ bị trễ nhìn rất mất mỹ quan. Khi thêm phần này vào thì các control sẽ hiển thị ra cùng 1 lúc, không có hiện tượng trễ.

Thứ Năm, 19 tháng 6, 2014

Bạn đã xây dựng được 1 website ASP.NET chạy hoàn hảo trên localhost và muốn đưa nó lên mạng Internet để "show hàng" với nhiều người. Việc tìm được 1 máy chủ - hosting ASP miễn phí, chất lượng tốt, ổn định là khá khó thay vì đối với hosting PHP thì lại có rất nhiều hosting miễn phí.

Sau khi tìm nhiều hosting ASP miễn phí, mình thấy chỉ có SOMEE.COM là trang cho chúng ta đăng ký 1 host miễn phí, chất lượng tốt, chạy được cả webform và mô hình MVC, chạy MS SQL khá ổn định. Đặc biệt hosting này không hay bị "die host" - vấn đề rất thường gặp ở các hosting PHP. Nói chung đây là 1 hosting rất phù hợp với những newbie đang tập tẹ vào lập trình ASP.NET.

Bài này mình sẽ hướng dẫn các bạn tạo 1 website trên somee và cách upload code lên host.

1. Đăng ký tài khoản trên somee.com

- Để đăng ký web hosting .NET miễn phí bạn vào trang http://somee.com/. Trong mục FREE .NET HOSTING chọn Learn More như hình bên dưới.
 Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting

Somee.com hỗ trợ ASP.NET từ phiên bản 1.1 đến 4.5, với 150MB bộ nhớ, 5GB băng thông hàng tháng, 15MB Microsoft SQL Server 2005, 2008 R2 hoặc 2012.

- Trong trang tiếp theo hiện ra. Click vào Order now như hình bên dưới để vào trang đăng ký.
Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting

- Điền đầy đủ các thông tin đăng ký như hình dưới đây. Yêu cầu Email phải chính xác để xác minh tài khoản. Mục Zip/Postal code nhập 70000 nếu ở TP. HCM, các mục: Primary phone, Secondary phone, Fax number không cần nhập cũng được. Sau đó click Register new user and continue.
Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting

- Trong trang mới hiện ra. Check vào 2 ô bên dưới. Sau đó Click Continue.
Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting

- Ở trang mới hiện ra. Chúng ta thiết lập những thông tin cơ bạn như tên website trong mục Site name; Operating system chọn Windows server 2012, ASP.NET verson chọn 4.5. Site tile và Site Description do bạn tự đặt. Sau đó click vào Create website.
Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting

- Trong trang tiếp theo hiện ra sẽ thông báo website của bạn đã được tạo thành công. Bạn click vào dòng Manage website để xem những thông tin cơ bản của webhosting somee miễn phí mà chúng ta vừa tạo.
Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting

- Những lần sau, để truy cập vào panel điều khiển của webhosting vừa tạo. Ta vào trang somee.com rồi chọn CONTROL PANEL như hình dưới đây. Sau đó đăng nhập với đăng nhập và tài khoản vừa đăng ký. Ở đây bạn có thể thấy thông tin FTP, IP hãy lưu ý chỗ này để liên kết FTP về sau.
Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting

- Như vậy vấn đề đăng ký ASP.NET webhosting miễn phí cơ bản hoàn tất. Và giờ chúng ta truy cập vào địa chỉ website mới vừa đăng ký. Ở ví dụ này là: http://www.nhatnghe.somee.com/. Và màn hình giao diện mặc định của website sau khi đăng kí như sau
Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting

2. Upload code lên host

- Nén tất cả code, resource, database của bạn vào 1 file .zip duy nhất để tiện cho việc upload

-  Trong màn hình quản trị control pannel của hosting, bên tay trái các bạn chọn File Manager, sau đó xoá trang Default.asp là trang mặc định của hosting đi. Các bạn xem hình bên dưới.
Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting

- Sau đó, bên tay phải ta chọn Upload, rồi tiến hành chọn file mà bạn vừa tải về được Upload lên hosting.
Đăng ký hosting miễn phí - Upload website ASP.NET lên hosting


Như vậy là bạn đã tạo được một trang web ASP.NET đơn giản trên 1 hosting miễn phí và đã up được code lên trên đó. 
Việc upload database, config website mình sẽ hướng dẫn trong 1 bài khác. 

Thân!

Nguồn tham khảo: doanweb, nhatnghe

Thứ Tư, 18 tháng 6, 2014

Đôi khi chúng ta cần lưu trữ thông tin nào đó liên quan đến người dùng, do người dùng cài đặt. Những thông tin này phải được lưu trữ một cách lâu dài, xuyên suốt từ phiên làm việc này đến phiên làm việc khác. Tức là ta phải có cách để lưu thông tin cài đặt của người dùng

Có nhiều cách để lưu thông tin cài đặt chương trình, sau đây là một số cách phổ biến, dễ sử dụng

1. Lưu thông tin cài đặt vào Registry

Registry là bộ nhớ lưu trữ các thông tin cài đặt của hệ điều hành cũng như của các phần mềm trên nó. Do vậy ta có hoàn toàn có thể lưu trữ và lấy các thông tin trên Registry.

Ưu điểm của cách này là truy xuất nhanh, ít bị thay đổi bởi người không hiểu biết, người dùng và chỉ có lập trình viên mới có thể biết được cấu trúc, vị trí lưu trên Registry.

Nhược điểm là khi muốn lưu, đọc dữ liệu trên Registry đều phải thực thi nhiều code và yêu cầu lập trình viên phải nắm vững cấu trúc của Registry. Các thông tin cài đặt này chỉ có tác dụng với máy đã tạo ra, khi copy ứng dụng sang máy khác thì thông tin cài đặt bị mất.

2. Lưu trực tiếp trên phần mềm

Nền tảng .NET FrameWork cho phép người dùng phần mềm chỉnh sửa và lưu các thông tin cài đặt ngay trên ứng dụng. Cách lưu thông tin cài đặt này rất dễ sử dụng, lập trình. Khi thêm 1 đối tượng setting thì .NET tự động sinh ra 1 class để quản lý các thông tin setting đó.

Để bắt đầu với cách này bạn click đúp vào "Properties" trong tab "Solution Explorer". Sau đó trong tab "Settings" hãy thêm những trường cài đặt mong muốn. Ở đây .NET hỗ trợ nhiều kiểu dữ liệu: bool, string, int, datetime...
Các cách lưu thông tin cài đặt cho ứng dụng C# - Apps setting

Sau khi đã lưu các thông số này, chúng ta đọc, lưu thông tin vào như sau:
// Đọc thông tin
string MySetting = ShowGridView.Properties.Settings.Default.MySetting;

// Ghi thông tin
ShowGridView.Properties.Settings.Default.CheckBox = true;
// Lưu lại
ShowGridView.Properties.Settings.Default.Save();

3. Lưu trên file bên ngoài

Một cách lưu trữ thông tin cài đặt nữa là lưu chúng ra một file text thông thường hoặc một file được mã hóa. Với cách này cũng có nhiều kiểu lưu trữ, tùy vào cách xử lý của lập trình viên:
  • Lưu vào 1 file text thông thường đặt cùng thư mục của ứng dụng. Các thông tin sẽ được lưu trữ theo tiêu chuẩn của lập trình viên. Sau đó lập trình viên phải đọc nội dung của file và xử lý chuỗi để lấy được các thông tin đã ghi trước đó.
  • Lưu vào 1 file XML với quy cách nhất định. Với cách này khi dùng các thủ tục đọc, ghi xml thì công việc đọc, lưu thông tin cài đặt sẽ dễ dàng hơn.
  • Lưu file vào thư mục AppData của từng User. Khi đó với các User khác nhau cùng sử dụng máy tính sẽ có những thông tin cài đặt khác nhau.
  • Lưu thông tin ra file .INI. Cách này bạn có thể tham khảo tại đây.
Vì các thông tin được lưu trên một file riêng biệt nên người dùng có thể dễ dàng thay đổi, hoán chuyển các thông tin cài đặt khi cần thiết (chỉ cần việc cut/paste file ra 1 chỗ khác).

Thứ Ba, 17 tháng 6, 2014

Trong các bài trước tôi đã giới thiệu tới các bạn cách làm việc với GridView, cách fill dữ liệu, Binding với GridView - Grid Control của DevExpress. GridView trở thành 1 đối tượng khá quan trọng với các dự án quản lý danh mục, và ta chắc hẳn phải sử dụng đến nó vì công dụng cũng như sự tiện lợi của DevExpress mang lại.

DevExpress thực sự là một bộ thư viện tuyệt vời với nhiều chức năng cũng như giao diện hoàn hảo. Đối với GridView, DevExpress không chỉ cung cấp khả năng làm việc tùy biến linh động nhiều chế độ mà chúng ta còn có thể tùy biến giao diện, tùy chỉnh ngôn ngữ của từng menu item trong GridView. Sau đây tôi sẽ hướng dẫn các bạn cách Việt hóa ngôn ngữ của GridView
Việt hóa giao diện GridView của DevExpress

Trong thư mục Project add một class với nội dung như sau:
class MyGridLocalizer : GridLocalizer
{
public override string GetLocalizedString(GridStringId id)
{
if (id == GridStringId.FindControlFindButton)
return "Tìm";
if (id == GridStringId.FindControlClearButton)
return "Bỏ";
if (id == GridStringId.GridGroupPanelText)
return "Kéo thả cột vào đây để gom nhóm";
if (id == GridStringId.MenuColumnSortAscending)
return "Sắp xếp tăng dần";
if (id == GridStringId.MenuColumnSortDescending)
return "Sắp xếp giảm dần";
if (id == GridStringId.MenuColumnClearSorting)
return "Bỏ sắp xếp";
if (id == GridStringId.MenuColumnGroup)
return "Gom nhóm theo cột này";
if (id == GridStringId.MenuGroupPanelShow)
return "Hiện hộp gom nhóm";
if (id == GridStringId.MenuGroupPanelHide)
return "Ẩn hộp gom nhóm";
if (id == GridStringId.MenuGroupPanelFullExpand)
return "Mở tất cả các nhóm";
if (id == GridStringId.MenuGroupPanelFullCollapse)
return "Thu tất cả các nhóm";
if (id == GridStringId.MenuColumnUnGroup)
return "Bỏ gom nhóm";
if (id == GridStringId.MenuColumnRemoveColumn)
return "Ẩn cột này";
if (id == GridStringId.MenuColumnShowColumn)
return "Hiện cột này";
if (id == GridStringId.MenuColumnColumnCustomization)
return "Tùy chỉnh cột";
if (id == GridStringId.CustomizationCaption)
return "Tùy chỉnh cột";
//if (id == GridStringId.CustomizationColumns)
// return "Kéo và thả cột vào đây để tùy chỉnh";
//if (id == GridStringId.CustomizationBands)
// return "Kéo và thả cột vào đây để tùy chỉnh";
//if (id == GridStringId.CustomizationFormBandHint)
// return "Kéo và thả cột vào đây để tùy chỉnh";
if (id == GridStringId.CustomizationFormColumnHint)
return "Kéo và thả cột vào đây để tùy chỉnh";
if (id == GridStringId.MenuColumnBestFit)
return "Căn chỉnh";
if (id == GridStringId.MenuColumnBestFitAllColumns)
return "Căn chỉnh tất cả";
if (id == GridStringId.MenuColumnFilterEditor)
return "Cài đặt lọc";
//if (id == GridStringId.MenuColumnFilter)
// return "menu filter";
if (id == GridStringId.PopupFilterCustom)
return "(Tùy chọn)";
if (id == GridStringId.PopupFilterAll)
return "(Tất cả)";
if (id == GridStringId.FilterPanelCustomizeButton)
return "Sửa lọc";
if (id == GridStringId.FilterBuilderCaption)
return "Cài đặt lọc";
if (id == GridStringId.FilterBuilderOkButton)
return "Đồng ý";
if (id == GridStringId.FilterBuilderApplyButton)
return "Áp dụng";
if (id == GridStringId.FilterBuilderCancelButton)
return "Hủy bỏ";
if (id == GridStringId.MenuColumnAutoFilterRowShow)
return "Hiện hàng lọc tự động";
if (id == GridStringId.MenuColumnAutoFilterRowHide)
return "Ẩn hàng lọc tự động";
if (id == GridStringId.MenuColumnFilterMode)
return "Chế độ lọc";
if (id == GridStringId.MenuColumnFilterModeDisplayText)
return "Văn bản";
if (id == GridStringId.MenuColumnFilterModeValue)
return "Giá trị";
if (id == GridStringId.CustomFilterDialogCancelButton)
return "Hủy bỏ";
//if (id == GridStringId.CustomFilterDialog2FieldCheck)
// return "2FieldCheck";
if (id == GridStringId.CustomFilterDialogCaption)
return "Hiển thị những hàng có:";
//if (id == GridStringId.CustomFilterDialogClearFilter)
// return "Clear";
if (id == GridStringId.CustomFilterDialogEmptyOperator)
return "(Chọn phép toán)";
if (id == GridStringId.CustomFilterDialogEmptyValue)
return "(Điền giá trị)";
if (id == GridStringId.CustomFilterDialogFormCaption)
return "Tùy chọn lọc tự động";
//if (id == GridStringId.CustomFilterDialogHint)
// return "fil hint";
if (id == GridStringId.CustomFilterDialogOkButton)
return "Đồng ý";
if (id == GridStringId.CustomFilterDialogRadioAnd)
return "Và";
if (id == GridStringId.CustomFilterDialogRadioOr)
return "Hoặc";
return base.GetLocalizedString(id);
}
}


Trong form chính (cần Việt hóa) ta thêm đoạn sau vào hàm khởi tạo class:
// Tùy biến giao diện Grid
GridLocalizer.Active = new MyGridLocalizer();

Lưu ý trong cả class và form đều phải:
using DevExpress.XtraGrid.Localization;

Với cách làm tương tự các bạn có thể Việt hóa các string khác của Dev.

Ví dụ: XtraMessageBox - một điều khiển khá quen thuộc các bạn có thể tham khảo tại đây

Chúc thành công.

Thứ Sáu, 13 tháng 6, 2014

Trong bài "[LINQ] LinQ là gì và tại sao nên dùng LinQ?" tôi đã giới thiệu đến các bạn sơ qua về LINQ và Binding, trong đó có 1 thành phần quan trọng đó là GridView của DevExpress. GridView có vai trò rất quan trọng trong việc hiển thị các dữ liệu dạng bảng, danh sách trong các phần mềm quản lý danh mục... và là thành phần không thể thiếu trong Binding dữ liệu.
Ở lần trước tôi chỉ giới thiệu các bạn về cách kéo thành phần GridView tự động từ cửa sổ "Data Source" phục vụ việc Binding, trong bài này tôi sẽ hướng dẫn cách làm việc với GridView thủ công, tùy chỉnh giao diện của nó - một trong những tính năng vượt trội, thành công lớn của DevExpress.

I. Tạo và thiết lập nguồn dữ liệu cho GridView

Tạo đối tượng GridView - Grid Control

Để tạo 1 đối tượng các bạn search trong toolbox "GridControl" và kéo vào form
Làm việc với GridView - Grid Control của DevExpress

Thiết lập nguồn dữ liệu cho GridView

Bây giờ chúng ta sẽ khai báo nguồn dữ liệu (data source) cho GridView, để gridview tự động lấy các giá trị và fill vào. Đây là tiện ích lớn nhất của việc Binding: có thể tự động lấy các dữ liệu điền vào grid và liên kết với phần detail
Để chọn data source cho gridView ta click vào hình tam giác ở góc trên cùng bên phải GridView. Trong phần "Choose Data Source" ta chọn data source đã có sẵn hoặc click chọn "Add Project Data Source" nếu chưa có.
Làm việc với GridView - Grid Control của DevExpress

Khi chọn Add Project Data Source các bạn có thể chọn thêm 1 database, service, object, sharepoint nhưng bạn nên chọn object để nó có thể kết nối tới file ".dbml" đã tạo trong phần giới thiệu LINQ.
Làm việc với GridView - Grid Control của DevExpress

Sau khi chọn object ta sẽ chọn bảng/view/đối tượng làm datasource cho GridView. GridView sẽ tạo ra các cột tương tự như các trường của bảng/view/đối tượng đã chọn.
Làm việc với GridView - Grid Control của DevExpress

Bây giờ chỉ cần thêm một vài câu lệnh để set nguồn dữ liệu thực cho datasource này. Việc này đã được giới thiệu trong bài giới thiệu LINQ.

Lưu ý:

  • Data Source cho GridView không chỉ là 1 table/view thực trong database mà có thể là 1 object ảo các bạn tạo ra trong file ".dbml" hoặc 1 đối tượng của Dataset... Với những object ảo này các bạn có thể tùy chỉnh, xử lý dữ liệu cho GridView.

II. Phần giao diện của GridView

Để tùy chỉnh giao diện, dữ liệu trong các hàng/ô của GridView ta có thể xem trong cửa sổ "Properties" tương ứng của GridView hoặc đơn giản hơn có thể mở giao diện tùy chỉnh của DevExpress:
Làm việc với GridView - Grid Control của DevExpress

Trong phần "Run Designer" này các bạn có thể tùy chỉnh một số thuộc tính của header, phần hiển thị của các ô, việc sửa đổi dữ liệu trong ô, sắp xếp theo cột, thay đổi màu sắc, font chữ... và cả các kiểu hiển thị dữ liệu trong từng ô. Chẳng hạn:

1. Tùy chỉnh giao diện

Thêm/bớt, thay đổi thứ tự các cột

Làm việc với GridView - Grid Control của DevExpress

Với "gridView1" ta vẫn có các sự kiện như ở GridView thông thường như: RowClick, RowCellClick...
Làm việc với GridView - Grid Control của DevExpress


Tùy chỉnh Layout

Làm việc với GridView - Grid Control của DevExpress

Thay đổi font chữ, căn lề của header, ô trong từng cột


Ấn giữ Ctrl để chọn nhiều cột 1 lúc. Các thuộc tính trong phần AppearanceCell & AppearanceHeader như font, Col Name, Text Options, Filter, Allow Edit, Visible... 

Phân biệt hàng chẵn, lẻ

Trong tab Views, phần Appearance > EvenRow, OddRow ta có thể thay đổi một số thuộc tính như màu nền, font chữ, text options... như ở phần header:
Làm việc với GridView - Grid Control của DevExpress

Kéo xuống phần OptionsView, chọn EnableApearanceEvenRow hoặc EnableApearanceOddRow bằng true
Làm việc với GridView - Grid Control của DevExpress

2. Kiểu dữ liệu hiển thị trong ô

Mặc định khi ta chọn Data Source cho GridView thì các cột trong GridView sẽ có 1 kiểu hiển thị dữ liệu tương ứng với kiểu dữ liệu của data source. Chẳng hạn nếu ở kiểu dữ liệu data là nvarchar thì control edit dữ liệu là textEdit (của Dev)... 
Giả sử bây giờ ta có 1 cột là idNhanVien nhưng ta muốn nó hiển thị là Họ tên của Nhân viên thì phải làm thế nào??!

Bằng cách dùng bảng NhanVien để tham chiếu từng idNhanVien với HoTen tương ứng ta sẽ lấy được họ tên của nhân viên ứng với id. Chắc hẳn việc này là rất khó khăn nếu ta dùng code thông thường, không dùng Binding vì phải tương tác qua lại giữa idNhanVien và HoTen trong tất cả các công việc sau này. Khi đã có Binding + DevExpress thì việc đó trở lên tương đối easy.

Ở Run Desinger, tab Columns, với cột tương ứng ta  chỉ cần thêm 1 đối tượng "ColumnEdit" tương ứng với kiểu dữ liệu, trường thông tin muốn hiển thị. Chẳng hạn muốn hiển thị họ tên của nhân viên, vì đây là trường có sẵn (chỉ việc select), số lượng có thể rất nhiều nên ta chọn ColumnEdit là một đối tượng SearchLookupEdit (giống kiểu ComboBox nhưng có tìm kiếm của Dev). Hay như với cột ghi thông tin ghi chú (độ dài nhỏ) thì ta có thể chọn là TextEdit để sau này có thể sử dụng các thuộc tính của TextEdit như MaxLength, Mask...

Quay trở lại với bài toán của chúng ta, sau khi đã thêm đối tượng SearchLoopupEdit cho cột idNhanVien thì ta có 1 đối tượng SearchLookupEdit thông thường, có thể đặt Data Source cho nó, trường hiển thị (DisplayMember), trường giá trị tương ứng (ValueMember). Ở đây ta đặt Data Source là 1 đối tượng trong file ".dbml" tham chiếu đến bảng NhanVien, DisplayMember là HoTen, ValueMember là idNhanVien.
Làm việc với GridView - Grid Control của DevExpress

Sau khi đặt ...bindingSource.DataSource = bla bla; thì kết quả được như này
Làm việc với GridView - Grid Control của DevExpress

Như vậy đã hiển thị được họ tên nhân viên và chức vụ tương ứng mà không cần dùng quá nhiều code, trong khi đó khi cần thiết vẫn có thể lấy được các giá trị id một cách dễ dàng.

Bây giờ nảy sinh một vấn đề nữa là khi ta edit cái SearchLookUp vừa tạo ở trên nó có giao diện không đẹp lắm, đặc biệt phiền phức nếu cái bảng nhân viên có vài chục trường mà ta chỉ muốn hiển thị một vài trường như họ tên, quê quán...
Như này chẳng hạn
Làm việc với GridView - Grid Control của DevExpress

Tất nhiên các kiểu hiển thị này chỉ cần quan tâm khi ta để dữ liệu ở cột dạng AllowEdit.

Để tùy chỉnh cũng không có gì quá phức tạp, chỉ là trên cái giao diện rối rắm vì quá nhiều chức năng của DevExpress khiến ta bối rối. Trong phần Columns > cột cần thay đổi > ColumnEdit (vừa tạo ở trên) > View
Làm việc với GridView - Grid Control của DevExpress

Để đơn giản ta click vào biểu tượng dấu 3 chấm "...". Nó sẽ ra một cửa số mới để tùy chỉnh cái SearchLookupEdit này tương tự với cái tùy chỉnh GridView ta làm việc từ đầu đến giờ.
Ta cũng có thể tùy chỉnh Layout, thêm/bớt cột, đặt caption, thay đồi font chữ header, phân biệt hàng chẵn/lẻ...
Làm việc với GridView - Grid Control của DevExpress

Và kết quả cuối cùng:
Làm việc với GridView - Grid Control của DevExpress

Enjoy!!!

Thứ Sáu, 6 tháng 6, 2014

Đôi khi bạn có 1 ảnh với kích thước nhỏ, bạn muốn resize nó (phóng to) thì cách được nghĩ đến đầu tiên là Photoshop.
Để có 1 bức ảnh scale không làm giảm chất lượng (tất nhiên là có giảm nhưng hạn chế) khá dễ dàng với Photoshop
 Cách phóng to ảnh không làm giảm chất lượng

Đây là 1 icon được resize từ 24x24 lên 512x512 trông không được hoàn hảo cho lắm nhưng cũng chấp nhận được với tỉ lệ resize này. Thậm chí nhờ việc resize này ta có thể gần như thấy rõ các pixel riêng rẽ của bức ảnh cũ, rất thích hợp cho việc thiết kế đồ họa theo phong cách "8 bit" cổ xưa  :D

Nếu không dùng thủ thuật này thì được 1 bức ảnh "mờ tịt" như này  :p
Cách phóng to ảnh không làm giảm chất lượng

Cách resize vô cùng đơn giản như sau:

Mở file ảnh bằng Photoshop

Chọn Image > Image Size (CTRL + ALT+ I)

Trong cửa sổ Size chọn kích thước cần resize, Constrain Proportions, > Nearest Neighbor (preserve hard edges) >> OK
Cách phóng to ảnh không làm giảm chất lượng


Cách khác

Nếu muốn resize với chất lượng tốt hơn bạn có thể dùng phần mềm hỗ trợ ngoài Photoshop. Chẳng hạn như Reshade.
Trang chủ: http://reshade.com/

Giao diện chương trình

Với chương trình này bạn có thể resize ảnh với nhiều tùy chọn khác nhau, làm sao để có được bức ảnh đẹp nhất.

Categories

Sample Text

Được tạo bởi Blogger.

Must Read

Biểu mẫu liên hệ

Tên

Email *

Thông báo *

Popular Posts

Video

Popular Posts

Our Facebook Page