13/01/2017

[Note] Một vài lệnh NuGet PowerShell Commands làm việc với Entity Framework

Thường được dùng khi làm việc với EF Code First!

/* Install Package cho project*/
Install-Package EntitFramework -Project MyProject.Data
UnInstall-Package EntityFramework -Project MyProject.Data
Update-Package EntityFramework -Project MyProject.Data

/* Install Package cho nhiều project*/
Get-Project MyProject.Data, MyProject.Repositories | Install-Package EntityFramework

/* Install Package cho tất cả project*/
Get-Project -All | Install-Package EntityFramework

/* Install Package cho project với sub name*/
Get-Project -All | where { $_.Name.EndsWith(".Data") } | Install-Package EntityFramework

/* Tạo migration cho project! */
Enable-Migrations -Project MyProject.Data

/* Thêm mới Migration cho project. Dùng khi thay đổi Models*/
Add-Migration -Project MyProject.Data

/* Apply Migration xuống Database. Dùng khi cập nhật thay đổi xuống database*/
Update-Database -Project MyProject.Data -Verbose

/* Roll Back Migration bằng tên*/
Update-Database -TargetMigration: "201701040423104_InitialUserRole"

/* Roll Back Migration bằng Index */
Update-Database -TargetMigration: 0

/* Có thể sửa, xóa Migration bằng tay. Becareful!*/

Hoặc dùng Manager Nuget packages for solution... thao tác với package


Created: 13/01/2017
Read now

28/10/2016

[WPF] Create Simple WPF App With MVVM and Validation - Part III

[WPF] Create Simple WPF App With MVVM and Validation - Part III

[Editing]
Trong 2 phần trước, ta đã có một demo cơ bản về cách sử dụng mô hình MVVM, sử dụng Entity Framework (Code First, EF này là EF core 7 nên một vài lệnh hơi khác một tí, nhưng nếu bạn quay lại đọc EF 6 thì vẫn không có gì trở ngại). Hôm nay, tiếp nối một phần rất quan trọng đó là Validation. Validation ở đây là muốn dữ liệu input, output không bị lỗi sai kiểu dữ liệu, mọi thứ nằm trong tầm kiểm soát giới hạn, nói chung là phải đúng như thiết kế ban đầu.


Trước khi vào ví dụ validate dữ liệu, ta cần biết một vài điều sau


Binding
Giúp lấy dữ liệu từ code-behind lên view XAML và ngược lại. Không nói đến việc gán dữ liệu kiểu truyền thống như Winforms bằng cách lấy Name của TextBox rồi gán Text cho nó trong code-behind, ở đây ta đang làm theo MVVM. Tất nhiên không ai cấm bạn đưa toàn bộ code từ ViewModel lên Code-Behind của file XAML, điều đó chẳng ảnh hưởng gì, chỉ việc Set DataContext = this, và ta có thể Binding như cũ. OK Nhưng sinh ra mô hình MVVM để đáp ứng nhiều nhu cầu, một trong số đó là tesing nên move hết code-behind về ViewModel. Một nhu cầu để sử dụng MVVM nữa là việc tách Code-Behind ra khỏi View là cho phép Designer thiết kế giao diện thoải mái trên Blend trong khi đó Coder vẫn đang miệt mải code logic và tesing, không ai phải chờ đợi ai cả!
(Đừng quên là bạn có thể Binding hầu như mọi Properties của Control nhé, chẳng hạn như Text, Color, Icon, Size, Event...)

Mode
Cho phép kiểu Binding
  • OneWay: Chỉ chuyển dữ liệu từ ViewModel  lên View
  • TwoWay: Vừa nhận dữ liệu lên View từ ViewModel như OneWay, vừa đưa dữ liệu xuống ViewModel từ View
  • OneTime: Giống OneWay nhưng nó chỉ làm 1 lần khi khởi tạo hoặc DataContext thay đổi lần đầu. 
  • OneWayToSource: Ngược lại OneWay, chỉ lấy dữ liệu từ View xuống ViewModel
  • Default: Cái này phụ thuộc vào control
  • Không khai báo Mode thì mặc định là OneWay

UpdateSourceTrigger
Thiết lập thời gian lúc nào thì được binding khi thay đổi dữ liệu. Nó chỉ làm việc khi mode là TwoWay hoặc OneWayToSource ngược lại sẽ không có tác dụng. Vì mục đích là kiểm soát input
  • Default: Mặc định hầu hết các thuộc tính là PropertyChanged chỉ có thuộc tính Text là LostFocus.
  • Explicit: Chỉ binding khi bạn gọi phương thức UpdateSource.
  • LostFocus: Binding ngay khi Lostfocus khỏi control
  • PropertyChanged: Binding ngay khi thuộc tính thay đổi. Ví dụ bạn set điều này cho thuộc tính Text thì mỗi khi gõ 1 ký tự, binding lập tức thực thi. Như vậy khá tốn hiệu năng, trừ trường hợp yêu cầu đặc biệt trong nghiệp vụ.

Converter
Cho phép bạn triển khai 2 phương thức, một là convert giá trị từ dưới ViewModel lên, thứ hai là convert giá trị từ View xuống ViewModel. Làm như vậy để mần chi?!

Ví dụ:
Giờ tôi muốn TextBox hiển trị giới tính Nam/Nữ tương ứng True/False. Thì bây giờ ta tạo một property kiểu bool dưới ViewModel sau đó binding cho Text property của TextBox.


Created: 28/10/2016
Read now

22/10/2016

[WPF] Create Simple WPF App With MVVM and Entity Framework Core - Part II

Qua Phần I, với demo đơn giản nhưng bao quát các phần cần có khi làm việc với MVVM rồi. Thực ra mô hình này cơ bản không có gì phức tạp cho người mới bắt đầu. Điều bạn cần biết, WPF sử dụng XAML để định nghĩa giao diện (UWP cũng sử dụng XAML là một trong các lựa chọn) và XAML giúp việc thiết kế giao diện trở nên linh hoạt hơn nhờ cú pháp của nó, cộng với công cụ Blend. XAML sẽ ánh xạ với C#, cho nên cái gì thiết kế trên XAML được thì tất nhiên sử dụng code để thay thế bình thường. Nhưng vậy thì còn gì vui, tốn thời gian, công sức trong khi sử dụng XAML triển khai ý tưởng nhanh hơn nhiều, ngoại trừ một số control bạn chắc chắn cần dùng code để xử lý.

Quay lại MVVM, với việc hỗ trợ Binding ta sử dụng mô hình này giúp mã nguồn sạch hơn, dễ bảo trì, kiểm thử. Bởi vì không có mã nào dưới phần giao diện, toàn bộ code xử lý, ngay cả các hành vi, sự kiện cũng được viết được dưới ViewModel. Trên mạng, các đồng nghiệp viết rất nhiều lợi ích và hạn chế của MVVM bạn có thể tham khảo thêm.



Phần này, tôi thử dùng Entity Framework để thao tác với database, CRUD các kiểu. Entity Framework thì nó có 3 cách tiếp cận, mỗi cách thì thêm kiểu có database hoặc chưa. Vì ta làm từ đầu nên giả sử ta chưa có database và cần tạo mới. Tôi thích sử dụng cách tiếp cận Code First và code toàn bộ, database không có tạo sẵn trên SQL Server. Máy tôi không có cài đặt SQL Server Manager Studio luôn, SQL Server thì chỉ chạy Sql LocalDb đi kèm Visual Studio, trong VS có Sql  Explorer thay thế tạm SQL Server Manager Studio cũng được. Nên dùng Code First tự generate database khi khởi tạo dựa vào Model của ta. Cách này được cho là ưng nhất, nhưng tốn công ngồi gõ.

Thực ra, các ứng dụng quản lý nhỏ, không cần phải sử dụng Entity Framework để xử lý đâu, thật dư sức và tốn kém. Nhưng đây là demo nên ta thử vài phần cơ bản cho vui...

Tham khảo:

Bắt Đầu

Yêu cầu:
  • Visual Studio 2015 Update 3
  • Latest version of NuGet Package Manager
  • Latest version of Windows PowerShell
  • .NET 4.5.1 or later (I'm on .NET 4.6)

Tôi sử dụng các công cụ với version gần đây nhất, nên nếu có thể bạn hãy cài các công cụ mới nhất. Tuy nhiên mọi thứ rất cơ bản nên không có thay đổi đáng quan tâm, bạn có thể linh động sử dụng trong các version thấp hơn.

1. Install Entity Framework

(EF có thể làm việc với nhiều Data Providers khác nhau, trong nội dung mà chúng ta đang làm việc sử dụng SQL Server)

Sử dụng lệnh power shell trong Visual Studio như sau:
(Tool | NuGet Package Manager | Package Manager Console)

RUN:
Install-Package Microsoft.EntityFrameworkCore.SqlServer
Install-Package Microsoft.EntityFrameworkCore.Tools –Pre
Figure 1: Install-Package from Nuget

Chúng ta sẽ cài thêm thư viện EF cho Project Models, chọn như hình trên. Bạn có thể sử dụng giao diện Nuget trực quan để cài đặt hoặc dùng code như đã nói.  (Nếu lỗi ngoài ý muốn, hãy Set as StartUp Project cho Models).

2. Create DataContext Class

Đây là nơi khai báo các model để EF hiểu...

a.) Tạo mới DataContext Class
Add reference: System.Configuration
using Microsoft.EntityFrameworkCore;
using System.Configuration;

namespace DataContext
{
    public class FunniesDataContext : DbContext
    {
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(ConfigurationManager.ConnectionStrings["FunniesConnection"].ConnectionString);
            base.OnConfiguring(optionsBuilder);
        }

        protected override void OnModelCreating(ModelBuilder modelBuilder)
        {
            base.OnModelCreating(modelBuilder);
        }

        public DbSet<Models.Department> Departments { get; set; }
        public DbSet<Models.Employee> Employees { get; set; }
    }
}

Connection bạn đặt ở App.config nhé!

b.) Add Migrations and Update Database
(Nên Set as StartUp Project cho Business.Model để tránh trường hợp lỗi khi không chạy được lệnh Migrations)
Run:
Add-Migration Your_Migration_Name
Update-Database

Figure 2.2.1: Add-Migration


Figure 2.2.2: View Database in SQL Server 

* Cứ mỗi lần chạy lệnh Update-Database các thay đổi model sẽ được apply xuống database.
* Bây giờ tôi muốn trong bảng Department có dữ liệu mẫu để test. Vì ta chỉ làm việc với bảng Employees, nên không tạo giao diện nhập dữ liệu cho Department.

OK

- Bạn thêm Migration 2 như sau:
  • Add-Migration Your_Migration_Name (Chạy lệnh này trước)
  • Sau đó bổ sung đoạn lệnh dưới đây vào file Migration mới tạo ở trên (Trong folder Models | Migrations)
protected override void Up(MigrationBuilder migrationBuilder)
{
    ///TODO: Seed data for Departments Table
    migrationBuilder.Sql("INSERT INTO Departments (Id, Name, Phone) VALUES   ('" + Guid.NewGuid() + "','Business', '84123456789')");
    migrationBuilder.Sql("INSERT INTO Departments (Id, Name, Phone) VALUES   ('" + Guid.NewGuid() + "','Development', '84987654321')");
}
  • Update-Database (Chạy tiếp lệnh này để apply migration mới xuống database nhé)
Figure 2.2.3: Add-Migration other

Figure 2.2.4: Update-Database again

3. Implemention Repositories

Trong Project Models tôi sử dụng folder Repositories để chứa code xử lý thao tác với database qua Entity Framework. Sau đó cho phép ViewModels sử dụng...

using System;
using System.Collections.Generic;
using System.Linq;

namespace Models.Repositories
{
    public class EmployeeRepository : IEmployeeRepository
    {
        public static EmployeeRepository Instance { get; } = new EmployeeRepository();

        public IEnumerable<Employee> GetAllEmployee()
        {
            using (var context = new DataContext.FunniesDataContext())
            {
                return context.Employees.ToList();
            }
        }

        public bool InsertEmployee(Guid id, string fullName, int age, string phone, string address, Guid departmentId)
        {
            using (var context = new DataContext.FunniesDataContext())
            {
                var employee = new Employee
                {
                    Id = id,
                    FullName = fullName,
                    Age = age,
                    Phone = phone,
                    Address = address,
                    DepartmentId = departmentId
                };

                context.Employees.Add(employee);

                try
                {
                    // Attempt to save changes to the database
                    context.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            }
        }

        public bool UpdateEmployee(Guid id, string fullName, int age, string phone, string address, Guid departmentId)
        {
            using (var context = new DataContext.FunniesDataContext())
            {

                var employee = context.Employees.Where(_ => _.Id.Equals(id)).FirstOrDefault();

                employee.FullName = fullName;
                employee.Age = age;
                employee.Phone = phone;
                employee.Address = address;
                employee.DepartmentId = departmentId;

                context.Employees.Update(employee);

                try
                {
                    // Attempt to save changes to the database
                    context.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            };
        }

        public bool DeleteEmployee(Guid id)
        {
            using (var context = new DataContext.FunniesDataContext())
            {
                var employee = context.Employees.Where(_ => _.Id.Equals(id)).FirstOrDefault();
                context.Employees.Remove(employee);

                try
                {
                    // Attempt to save changes to the database
                    context.SaveChanges();
                    return true;
                }
                catch
                {
                    return false;
                }
            };
        }
    }
}

- Get dữ liệu nhớ dùng System.Linq để ToList() hoặc FirstOrDefault() nhé. Xem kĩ trong code trên
- Phần này nó cũng đơn giản, chỉ mới có các hàm CRUD.  Bạn có thể xem thêm trong mã nguồn cuối bài viết này.
- Trong ViewModel bạn khai báo để sử dụng Repository như sau (Chúng ta sử dụng interface để gọi)
- Tôi split file code cho dễ nhìn thôi, các bạn không hiểu thì có thể nhìn số line của code.

Figure 3: Use Repositories


4. Query Data

Database đã khởi tạo xong, giờ ta có thể nhập xuất dữ liệu được rồi
(Nhớ Set as StartUp Project cho Business.App để chạy demo)

(*) Vì ta có các Project tách biệt, nên bạn cần khai báo connectionStrings trong App.Config của các project như nhau (Thật ra project ViewModel không cần khai báo đâu nhé)

Figure 4: Add Connection Strings

OK
- Đến bước này, bạn có thể get dữ liệu lên giao diện rồi.
- Các thao tác thêm, sửa, xóa thông qua command như Phần I, chỉ là phần này làm việc với Database
- Logic thao tác CRUD thì bạn tự tìm hướng phù hợp với mình. Tùy mỗi dự án nó lại khác nhau, tôi chỉ làm mẫu đơn giản thôi.
- Vẫn chưa validate nên nhập sai kiểu dữ liệu, hoặc query hỏng là lỗi đấy nhé, sang phần khác ta sẽ bổ sung. Không nên làm 1 lần rất rối

5. Final

Trong phần này, ta chỉ làm quen cách dùng Entity Framework, tôi dùng phiên bản Entity Framework Core nên hơi khác chút xíu. Nhưng bạn có thể tự nghiên cứu để làm việc với các phiên bản thấp hơn, vì đây chỉ là cơ bản.
Lưu ý: 
Nếu bạn sử dụng source code. Chạy lệnh Update-Database để khởi tạo và chỉnh lại ConnectionString trong App.config




Created: 11/10/2016
Updated: 15/10/2016
Updated: 16/10/2016
Updated: 21/10/2016
Updated: 22/10/2016
Source Code: Tải về tại đây
Read now

09/10/2016

[WPF] Create Simple WPF App With MVVM - Part I

Để tìm kiếm một kiến thức có hệ thống về lập trình WPF, ngoài việc research online, tham khảo các samples của Microsoft, các đồng nghiệp trên các trang như stackoverflow, codeproject, google,bing hoặc bravohex.. ta cũng nên review một tí documents từ các nguồn. Nhưng điều tốt  nhất là tạo cho mình một demo đơn giản, dễ hiểu từ một mớ thông tin kể trên. Cho nên  tôi sẽ đi demo lại một ứng dụng nhỏ, cơ bản và post lên blog này. Nếu bạn đang chung mục tiêu tìm kiếm, mời xem tiếp nhé. Toàn bộ nội dụng demo, ta sẽ đi qua các phần như sau:



Môi trường phát triển:

  • Visual Studio 2015
  • WPF 4.5/ C# 6.0 
  • Windows 7 or higher (I'm working on Windows 10 Pro/64bit with .NET 4.6)

Có một điều bạn cần biết, các version của WPF, ASP.NET, UWP... và ngôn ngữ như C# phụ thuộc vào phiên bản Visual Studio bạn cài đặt và Windows có hỗ trợ không.
Chẳng hạn như tôi dùng Visual Studio 2015 đương nhiên hỗ trợ sẵn C# 6.0. Nhưng nếu build  lại trên Visual Studio 2013 một cách chính thống thì vài rắc rối nhỏ sẽ xảy ra. Vô số chức năng C# 6.0 sẽ lỗi toàn tập.
Thật ra, tôi quan tâm C# version mới nó coding ngắn gọn, nhanh hơn, đẹp hơn, các vấn đề hiệu năng ta không kể ở đây. Cái gì mà nó phức tạp thôi bỏ qua...
(Nếu Visual Studio của bạn không code được C# 6.0 thì convert lại 1 tí. Cũng không nhiều chỗ... )

Hoặc bạn có thể tải bản Visual Studio Community 2015 miễn phí để sử dụng. OK Let's go...

Read now

01/10/2016

[Share & Use] Windows App Studio UWP Samples

Figure 1: Main Page of App Sample

ng dụng UWP này, là ví dụ về các Custom Control, Classes dành cho mọi người tham khảo. Bạn có thể xem chi tiết mã nguồn từ Github và các Control, Classes cũng có sẵn trên Nuget Package nếu bạn cần.
(Yêu cầu: Cần  Windows 10/ Mobile để tải app)

GET: Windows 10 App Stores


GET: Github Repository


GET: Nuget Package:

Dựa vào các ví dụ trong app trên, nó sẽ mang lại nhiều kinh nghiệm và hứng thú cho bạn trong lập trình các ứng dụng UWP nếu bạn quan tâm.

Ngoài ra, tôi sẽ hướng dẫn bạn sử dụng mã nguồn trên để có được khung giao diện menu Hamburger cơ bản như hình.

Figure 2: Main Page of Sample 

Mục tiêu của ứng dụng mẫu trên là demo các custom controls, classes. Nhưng bạn có thể tự mình apply chúng vào code của mình sau. Còn mục tiêu của hướng dẫn tiếp theo dưới đây chỉ muốn sử dụng menu hamburger trong 1 rừng code của source code trên. Đó là cái khung giao diện của app sample này, từ đó bạn muốn code lại các tính năng của nó thì sẽ dễ dàng hơn. Sẽ lấy y nguyên  mã nguồn trên nhé, không thêm bớt đoạn code nào.  Okay let's go...
Read now

27/04/2016

[C# .NET] Classes and Objects

Trong ngôn ngữ lập trình hướng đối tượng (OOP), class chính là một data-type định nghĩa các biến và phương thức cho khai báo một object. Hay nói cách khác, class định nghĩa data-type cho object, tuy nhiên class không phải là một object. Một object là một thực thể dựa trên class, hay còn gọi là một khởi tạo (instance) của một class.

Value Types

Trong ngôn ngữ C#, có 2 cách để lưu trữ dữ liệu là bằng ReferenceValue.
Một vài kiểu data-type như int, double được sử dụng để khai báo các biến, đó chính là value-type. Chúng được lưu trữ trong bộ nhớ (memory) có địa chỉ được gọi là Stack.

References Types

Kiểu reference dùng để lưu trữ các đối tượng (object). Khi bạn khởi tạo một đối tượng, dữ liệu của nó được lưu trữ trên bộ nhớ được gọi là Heap. Nhưng địa chỉ (address) dẫn đến nó được lưu ở Stack, nó chứa địa chỉ (memory address) đến đối tượng thực tế trên Heap. Đó là lý do gọi là reference-type...

  • Stack: sử dụng để cấp phát bộ nhớ tĩnh (static memory), bao gồm cho tất cả value-types của bạn.
  • Heap: sử dụng để cấp phát bộ nhớ động (dynamic memory), bao gồm các objects tùy chỉnh mà có thể cần thêm bộ nhớ trong quá tình hoạt động (runtime).

Tham khảo thêm:

Created: 37/04/2016
Read now

21/04/2016

[C# .NET] Convert Between Hexadecimal, Decimal, Octal, Binary With C#

[C# .NET] Convert Between Hexadecimal, Decimal, Octal, Binary With C#

Để chuyển đổi qua lại giữa các hệ cơ số trong lập trình C# bạn có thể tham khảo các phương thức sau đây.

Bài liên quan
Hexadecimal, Decimal, Octal, Binary


1. Hex

a.) Decimal

//Hex to Dec
var hex = "7E0";
var dec = Convert.ToInt32(hex, 16); //2016
//Dec to Hex
var hex2 = dec.ToString("X"); //7E0

b.) Octal

//Hex to Octal
var hex = "7E0";
var dec = Convert.ToInt32(hex,16); //2016
var oct = Convert.ToString(dec,8); //3740
//Octal to Hex
var dec2 = Convert.ToInt32(oct, 8); //2016
var hex2 = dec2.ToString("X"); //7E0

c.) Bin

//Hex to Bin
var hex = "7E0";  
var dec = Convert.ToInt32(hex,16); //2016
var bin = Convert.ToString(dec,2); //0111 1110 0000
//Bin to Hex
var dec2 = Convert.ToInt32(bin, 2); //2016
var hex2 = dec2.ToString("X"); //7E0

2. Dec

a. Octal

//Dec to Octal
var dec = 2016;
var oct = Convert.ToString(dec,8); //3740
//Octal to Dec
var dec2 = Convert.ToInt32(oct, 8); //2016

b. Bin

//Dec to Bin
var dec = 2016;
var bin = Convert.ToString(dec,2); //0111 1110 0000
//Bin to Dec
var dec2 = Convert.ToInt32(bin, 2); //2016


3. Octal

//Oct to Bin
var oct = "3740";
var dec = Convert.ToInt32(oct,8); //2016
var bin = Convert.ToString(dec, 2); //0111 1110 0000
//Bin to Oct
var dec2 = Convert.ToInt32(bin, 2); //2016
var oct2= Convert.ToString(dec2, 8); //3740


Created: 21/04/2016
Read now

13/04/2016

[UWP] Use Entity Framework 7 and SQLite in Windows Universal Apps

[UWP] Use Entity Framework 7 and SQLite in Windows Universal Apps

Entity Framework nay hỗ trợ nền tảng Universal Windows Platforms, tuy vẫn còn nhiều issues nhưng cơ bản mọi thứ hoạt động khá trơn tru. Bạn có thể làm quen trước  thông qua ví dụ trên trang giới thiệu về EF: efproject.net

Với EF bạn có thể làm việc với các Database Provinders sau:
  • Microsoft SQL Server
  • SQLite
  • Microsoft SQL Server Compact Edition
  • Npgsql (PostgreSQL)
  • IBM Data Servers
  • InMemory (for testing)

Bạn có thể theo dõi bài viết trên trang giới thiệu để thực hiện ví dụ mẫu, tuy nhiên dưới đây là một vài lưu ý để bạn không gặp phải khó khăn khi thực hiện nó.

- Có thể sử dụng SQLite để thực hiện demo thêm sửa xóa.

- Chỉ cần 2 Install-Package như trên trang chủ đã hướng dẫn
Install-Package EntityFramework.SQLite –Pre
Install-Package EntityFramework.Commands –Pre
- Bạn có thể kết nối tới database một trong các nhà cung cấp đã nói ở trên nếu bạn có server riêng. Nếu không bạn có thể dùng InMemory để test hoặc sử dụng SQLite, nó sẽ tạo dữ liệu cục bộ trên thiết bị của bạn.

- Để không bị lỗi không hay khi tạo ví dụ mẫu, bạn nên tạo mới một blank project để không thiếu các thư viện cần thiết

- Add đoạn mã sau vào file Properties/Default.rd.xaml để giả quyết một issue của EF, điều này sẽ sớm được giải quyết
<!-- Add your application specific runtime directives here. -->
<Type Name="System.Collections.ArrayList" Dynamic="Required All" />

- Lệnh Add-Migration bạn chỉ thực hiện lần đầu sau đó bạn có thể đặt đoạn mã dưới đây:
using (var db = new YourContext())
{
     db.Database.Migrate();
}
Trong file App.cs để EF tự động cập nhật các thay đổi, nếu không bạn tự Add-Migration khi model thay đổi.

- Bạn có thể delete tất cả Migrations để làm lại và uninstall app trên thiết bị của bạn

Created: 13/04/2016
Read now

03/04/2016

[UWP] Draw a Circle Sector With Path

Hình tròn (Circle) có thể được tạo một cách dễ dàng bởi các control có sẵn trong Universal App. Dưới đây là liệt kê một vài control cơ bản mà bạn có thể sử dụng:

  • Ellipse với Width = Height
  • Rectangle với Width = Height, RadiuX = RadiusY= Width/2
  • Grid/Border với Width = Height, CornerRadius =  Width/2

Vậy để vẽ một Sector của hình tròn thì sao? Đừng lo lắng, bạn có thể sử dụng Path để vẽ chúng. Path thực chất chỉ chứa các dữ liệu... để tạo nên  một hình phức tạp, thuộc tính chứa dữ liệu đó là Data.

Tìm hiểu thêm:


Nếu bạn làm việc bằng công cụ thiết kế trực quan thì dữ liệu Data tự tạo ra gồm một chuỗi các ký tự, thoạt trông khá khó hiểu. Nhưng nó chỉ là tọa độ, độ dài của các point, line và đều bắt đầu với một ký tự đại diện để phân biệt.

Tìm hiểu thêm:


Trong một yêu cầu mới với nhiều thay đổi, ví dụ như tạo Sector của hình tròn với bán kính (Radius), góc (Degrees), vị trí (Start angle - End angle) tùy biến. Có lẽ sử dụng code-behind sẽ dễ dàng hơn.

Figure 1: I had drawn on Visio 2016

A. Input

Radius: Nhập vào độ dài bán kính.
Angle/Percent: Nhập vào góc hoặc phần trăm Sector muốn tạo.
Start Angle: Tọa độ bắt đầu của Sector. Mặc định thì tọa độ 0 như trên hình
End Angle: Không cần thiết, ta dựa vào angle/percent + start angle ta có thể biết end angle.

B. Request

CenterPoint: Tọa độ vị trí trung tâm của hình tròn, bạn chọn ở đâu thì hình tròn sẽ nằm ở đó.
Radius: Độ dài bán kính
StartPoint: Tọa độ điểm bắt đầu của Arc, ta có công thức
var startX= centerPoint.X + radius * Math.Cos(startAngle * Math.PI / 180);
var startY = centerPoint.Y + radius * Math.Sin(startAngle  * Math.PI / 180);
EndPoint: Tọa độ điểm cuối của Arc, ta có công thức
var endX= centerPoint.X + radius * Math.Cos(endAngle * Math.PI / 180);
var endY = centerPoint.Y + radius * Math.Sin(endAngle  * Math.PI / 180);
Size: Width/Height của Arc, ta dựa vào Radius, do đó ta có Size(Radius,Radius)
Chú ý: Nếu bạn thay thế Angle/Percent bằng Radian thì rút gọn Math.PI/180 bằng Math.PI

C. Implementation Method: C#

private PathGeometry CreateCircleSectorAtPoint(double center, double radius, double percent, double startAngle)
{
    //Request
    var centerPoint = new Point(center, center);
    var angle = 360 * (percent / 100);
    var endAngle = startAngle + angle;

    var startX = centerPoint.X + radius * Math.Cos(startAngle * Math.PI / 180);
    var startY = centerPoint.Y + radius * Math.Sin(startAngle * Math.PI / 180);

    var endX =  centerPoint.X + radius * Math.Cos(endAngle * Math.PI / 180);
    var endY =  centerPoint.Y + radius * Math.Sin(endAngle * Math.PI / 180);

    //Path Figure

    PathFigure pf = new PathFigure();
    pf.StartPoint = new Point(startX, startY);
    pf.IsClosed = true;
    pf.IsFilled = true;

    //ARC
    ArcSegment arc = new ArcSegment();
    arc.Point = new Point(endX, endY);
    arc.Size = new Size(radius, radius);
    arc.IsLargeArc = percent > 50 ? true : false;
    arc.SweepDirection = SweepDirection.Clockwise;

    // Line Segment
    LineSegment ls = new LineSegment();
    ls.Point = new Point(center, center);

    // Add child
    PathSegmentCollection psc = new PathSegmentCollection();
    psc.Add(arc);
    psc.Add(ls);

    pf.Segments = psc;
    PathFigureCollection pfc = new PathFigureCollection();
    pfc.Add(pf);

    PathGeometry pg = new PathGeometry();
    pg.Figures = pfc;

    //Return Data
    return pg;
}

D. Result

Figure 2: Demo Circle Sector On Visual Studio 2015 - UWA

Done :)

E. Read more

Figure 3: About Sigment and Sector
See calculate for Sigment
Warning:
The argument to Math.Sin(a) and Math.Cos(a) is in radians, not degrees. To convert, multiply by π/180:
var a = Math.Sin(27);
// Result: 0.956375928404503
var b = Math.Sin(27 * Math.PI / 180);
// Result: 0.453990499739547
Try it in Visual Studio and your calculator!

Created: 03/04/2016
Updated: 04/04/2016
Updated: 05/04/2016
Full Source code: DrawCircleSector
Read now