Browsed by
Category: Coding

Bắt HTTP Request trên máy ảo iOS

Bắt HTTP Request trên máy ảo iOS

Hoàn cảnh

Mấy nay đang đánh vật với cái app gửi rồi nhận HTTP request các kiểu. Phải là đang xài Windows thì còn đỡ, có Fiddler thần thánh thì đừng hỏi (không có Fiddler chắc không tồn tại một số không nhỏ các app trên WP Store :3 ). Nhưng mà trên Mac thì không có sẵn vậy. Mặc dù source .NET core đã public nhưng mà chắc vẫn phải chờ một thời gian nữa trước khi các app .NET được port qua cho Mac. Hàng free như Wireshark thì không đủ trình xài, hàng chất như Charles thì không có tiền xài. Thành ra bữa giờ đều phải xài dev tool của trình duyệt, ngồi bắt request rồi code giả lập trở lại.

Rắc rối xảy ra khi vừa nãy gửi một cái GET request từ code, đặt breakpoint trong callback nhưng hoàn toàn không thấy gọi về. Cay! Quyết tâm đào lại Google một lần nữa, lần này thì đào được cái Burp Suite này. Thằng này bản full của nó cũng một đống tiền, hên cái là bản free vẫn đáp ứng đủ yêu cầu. Thế là kéo về chiến.

Cài

Thằng này viết bằng Java nên các bạn chịu khó cài JRE các kiểu trước khi chạy. Chạy được rồi thì vẫn chưa xài được đâu, phải vào config cho nó tí. Trong giao diện chính của nó, các bạn đổi qua tab Proxy (và chúng ta cũng chỉ chủ yếu là việc ở tab này thôi), trong tab Options, các bạn chọn item mặc định có sẵn trong khung Proxy Listeners rồi click Edit. Cửa sổ khác hiện ra, các bạn tick vào tùy chọn All interfaces. Thế là xong, cứ ok hết các kiểu, nó có hiện thông báo gì cũng mặc kệ nó.

Tiếp theo là config cho máy. Các bạn vào System References > Network > chọn connection nào mà bạn muốn theo dõi rồi nhấn Advanced. Cửa sổ hiện ra, các bạn đổi qua tab Proxies rồi enable cái Web Proxy (HTTP) lên, ở phần Web Proxy Server, các bạn tiến hành set Server như hình, port thì phải giống với cái port mới config khi nãy bên thằng Burp Suite. Nếu các bạn muốn bắt thêm HTTPS thì enable luôn thằng ở dưới rồi set thông số tương tự. (Nhưng mà tí nữa xài xong thì nhớ disable tụi này đi :v)

Giờ quay lại thằng Burp Suite, thử reload vài trang bằng trình duyệt để test, thằng Burp Suite nó sẽ bắt hết HTTP request rồi nhét vào tab HTTP history. Đến đây muốn xài với máy ảo thì các bạn tiến hành restart máy ảo (nếu đang chạy) hoặc chạy nó rồi xài. Lưu ý là giữa các lần thay đổi proxy cho máy thì chúng ta phải restart máy ảo thì thay đổi mới có tác dụng.

Nếu

Câu hỏi là: máy ảo chạy ngon rồi, giờ giả dụ deploy ra chạy trên máy thật rồi muốn bắt thì phải làm sao? Cái này cũng không khó, trên iOS device các bạn connect vào cùng một mạng với Mac, sau đó set Manual Proxy bằng cách vào Settings > Wi-Fi > chọn mạng đang connect, kéo xuống dưới cùng rồi set thông tin server + port tương ứng.

Câu hỏi tiếp theo là: port thì biết rồi, y chang khi nãy, còn server thì lấy đâu ra? Câu trả lời là server chính là local IP của Mac, muốn xem cái này thì trên Mac các bạn mở Network References ra (ở đâu chắc khỏi nói nữa ha :v), IP nó sẽ nằm ngay dưới Connection Status.

Kết

Mình vừa xài thử, tất nhiên là không đã như Fiddler, nhưng mà nói chung cũng thỏa mãn, hàng free không dám đòi hỏi nhiều :3 Có điều cài xong ngồi bắt request cho đã vẫn không thấy callback được gọi. PM hỏi thánh thì thánh chỉ, hóa ra là do chơi ngu, đặt breakpoint trong success callback mà không đặt trong failure callback :'( request bị lỗi, nó không gọi về là phải :'(

Chúc các bạn thành công!

YOLO \m/

 

[Xcode] Git và xử lý xung đột với file .pbxproj

[Xcode] Git và xử lý xung đột với file .pbxproj

Vướng

Mình chuyển qua dùng Git cũng được một thời gian, nhưng cũng chỉ dùng như một trình sao lưu code, gần đây thì bắt đầu tập thói quen branch theo các flow phổ biến. Về phía Xcode, Xcode đã tích hợp luôn Git vào từ phiên bản 4, rất tiện để dev (mặc dù mình thấy xài Terminal thì tiện hơn).

Nhưng tách branch lại sinh ra vấn đề khác.

Trong một project gần đây, mình tách một branch usermodel để build user model, mình tách một branch facebooklogin để nhét cái tính năng đăng nhập bằng Facebook. Sau khi dev xong cả 2, mình tiến hành merge usermodel vào facebooklogin (đăng nhập xong thì phải có cái gì đó để lưu thông tin user chứ).

Conflict!

Và cụ thể là ở file project.pbxproj.

Tìm

Đào Google một hồi thì biết project.pbxproj là một file có thể đọc dưới dạng text, nội dung của nó được cấu trúc dưới dạng namevalue, thằng Apple gọi nó là Property Lists, không hẳn giống nhưng mà có chung tư tưởng với JSON. Nhiệm vụ của con khủng long này lưu lại tất cả cấu trúc project hiện tại của bạn: gồm có những file nào, group nào, cái nào nằm trong cái nào, cái nào link cái nào, blah blah blah. Vậy nên việc merge 2 branch này và gặp conflict cũng là điều dễ hiểu, nhất là khi một branch add một đống các file này còn branch kia lại add một đống các file khác. Về mặt lý thuyết thì chúng ta vẫn có thể xử lý conflict bằng tay (đằng nào thì nó cũng có cấu trúc mà :3), nhưng mà thử mở con khủng long này lên thì choáng cmnl :v Bạn nào bảo merge tay không sao thì còn khủng long hơn cả nó :v

Gỡ

Google thêm tí thì đào được giải pháp từ chỗ này, cách làm là tạo một file .gitattributes, nhét vào trong thư mục gốc của project (là cái thư mục có chưa file .xcodeproj ấy :3), file đó sẽ có nội dung như sau:

*.pbxproj binary merge=union

Save lại là xong, giờ merge ngon lành.

Hiểu

Lệnh trên có 2 phần:

  • Phần đầu là tên các file sẽ được áp dụng, cụ thể ở đây là tất cả những file có ext là pbxproj.
  • Phần sau sẽ là các flag:
    • Flag binary : xem file này như là một file binary. Về bản chất, flag binary  tương đương với việc xài kết hợp cùng lúc flag -crlf  (không động đến CRLF) và flag -diff  (không đụng đến khi so sánh).
    • Flag merge=union : lúc merge thì nhét cả 2 cái vào 1 hộ tao.

Túm lại là câu lệnh có nghĩa là: với những file có đuôi pbxproj thì bỏ qua mấy cái vấn đề với CRLF, lúc diff thì đừng có lên nó ra, còn lúc merge thì cứ nhét chung cả 2 cái vô một.

Thế là xong :v chúc các bạn thành công :3

YOLO \m/

Cài đặt và tạo project Cocos2d-x trên Mac OS

Cài đặt và tạo project Cocos2d-x trên Mac OS

Mấy nay tự dưng nổi hứng muốn ngâm cứu tí về game cho iOS. Dạo một vòng thì một số giải pháp được đưa ra:

  • SpriteKit: thằng này của Apple cho không biếu không, làm nhanh gọn lẹ, phải cái chỉ hỗ trợ iOS 7, thế nên là next, nghe đâu 30% tổng số máy iPhone hiện giờ vẫn còn chạy iOS 6 trở xuống.
  • Unity: ngon, và khủng, phải cái muốn xài full tính năng thì phải trả phí, mặc dù không biết có xài hết tính năng không nhưng mà cứ có phí là next.

Nên là mình quyết định sẽ đâm đầu vào Cocos 1 chuyến, nhanh gọn, lại là hàng free. Đến đây lại có thêm 2 lựa chọn khác (rắc rối vãi):

  • Cocos2D: mainly target iOS nên vì thế sẽ phát triển hoàn toàn bằng Objective-C (code Obj-C một thời gian tự dưng thấy yêu hẳn), tất nhiên cũng sẽ hỗ trợ mạnh mẽ Swift (cứ xem cái tên miền là thấy).
  • Cocos2d-x: cross-platform mạnh mẽ hơn, nhưng sẽ dev bằng C++.

Cocos2D về mặt lý thuyết thì vẫn là cross-platform, nhưng nếu muốn đẻ thêm 1 bản Android thì phải thông qua Apportable. Mình chả biết nó là thằng nào, lại chả thấy đề cập đến việc port qua Windows Phone, cho nên là next. Mình sẽ dùng Cocos2d-x, mặc dù dev bằng C++ thì mệt, nhưng mà *nghe đâu* thằng này hỗ trợ quản lý bộ nhớ hết rồi, nên đại khái là không xoắn.

Thế là tải source về các kiểu, chuẩn bị hết rồi, nhưng ngay bước đầu tiên, bạn Cocos2d-x (từ giờ sẽ gọi là CCX) đã tát cho mình ngay một phát rất nhanh và mạnh: không cài đặt được

Mình thử dán mắt vào để soi, nhưng rõ ràng là không sao chỗ nào cả. Sau một hồi đào xới Google thì mình mò được cái StackOverflow, bảo là từ bản 3.1 trở đi phải cài bằng cách khác, chứ cách cũ không còn xài được nữa.

Cài đặt

Hóa ra hướng dẫn tất cả đều nằm trong file README.md trong thư mục tải về, mịa nó trước giờ có bao giờ đọc file README đâu.

Và cụ thể như sau:

$ cd [ĐƯỜNG_DẪN_ĐẾN_THƯ_MỤC_VỪA_TẢI]
$ ./setup.py

Trong quá trình cài đặt nó sẽ hỏi thêm vài thành phần khác nữa như NDK các kiểu, ở đây mình chỉ target iOS nên chỉ cần Enter để bỏ qua mấy cái này.

Sau khi cài đặt xong, nó sẽ yêu cầu bạn execute thêm một câu lệnh nữa để các biến hệ thống nó làm việc, cứ việc làm theo, chả mất gì (thực ra nếu không làm thì lãnh hậu quả ráng chịu =)))) ).

Tạo project

Việc tạo project không còn đơn giản như các phiên bản trước: chỉ cần mở Xcode và chọn các template vừa được cài sẵn. Bây giờ bạn phải tạo project bằng dòng lệnh. Cú pháp đầy đủ như sau.

$ cocos new [-h] [-p PACKAGE_NAME] -l {cpp,lua,js} [-d DIRECTORY]
            [-t TEMPLATE_NAME] [--ios-bundleid IOS_BUNDLEID]
            [--mac-bundleid MAC_BUNDLEID] [--no-native]
            [PROJECT_NAME]

Có rất nhiều flag để dùng, để hiểu rõ hơn về các flag, các bạn có thể dùng lệnh

$ cocos new -h

Ở đây, mình sẽ tạo một project mới tên là TestGame, có package name giống với bundle id là com.quangltp.TestGame, sẽ viết bằng C++, và lưu vào đường dẫn /Volumes/Data/Projects, nên câu lệnh cụ thể mình sẽ xài là

$ cocos new TestGame -p com.quangltp.TestGame --ios-bundleid com.quangltp.com.TestGame -l cpp -d /Volumes/Data/Projects

Câu lệnh này nhìn thì kinh vậy, chứ bản chất của nó chỉ là copy project mẫu có sẵn trong đống vừa tải về khi nãy, dán vào đường dẫn bạn chỉ định, đồng thời đổi tên các thứ linh tinh theo ý bạn thôi.

Sau đó…

Thế là xong. Giờ bạn có thể thử build và chạy thử bằng Xcode hay bằng dòng lệnh, tùy, hoặc có thể dev theo các tut mà bạn tìm được.

Bài này chủ yếu là để mình chia sẻ giái pháp với các bạn gặp rắc rối giống mình, không có ý định viết sê ri các bài hướng dẫn hay gì cả.

Chúc các bạn may mắn!

YOLO \m/

Xử lý nhanh hình ảnh trong thiết kế giao diện Windows Phone

Xử lý nhanh hình ảnh trong thiết kế giao diện Windows Phone

Giao diện ngon nghẻ luôn mang lại những thành công nhất định cho một ứng dụng Windows Phone (WP).

Trong thiết kế giao diện, ngoài bố cục, màu sắc hợp lý, việc trang trí linh tinh như chèn hình nền,… cũng có tác dụng không nhỏ.

XAML mặc định có hỗ trợ Path, Path là một công cụ vô cùng hữu hiệu để làm việc với các đối tượng vector. Tuy nhiên, việc dùng Path không phải dễ, nếu không thành thạo, ngay cả việc vẽ những hình khối đơn giản cũng sẽ tốn của bạn một đống thời gian.

Quay lại với vấn đề, giả dụ mình muốn chèn một hình như sau vào ứng dụng, khổ cái là hình mình muốn chèn chỉ có độ phân giải rất nhỏ, nếu zoom lên 1 tí là vỡ tè le, như thế này

Vì ở đây, hình ảnh mình muốn chèn khá đơn giản, không quá cầu kì phức tạp nên mình quyết định sẽ sử dụng các tool có sẵn, vector hóa nó rồi sau đó import vào XAML. Hiện có rất nhiều công cụ hỗ trợ vector hóa hình ảnh, để cho tiện, mình sử dụng luôn một tool online có sẵn là Vector Magic. Việc sử dụng rất đơn giản, bạn lên side đó, upload ảnh cần xử lý lên, nó sẽ xử lý cho bạn, sau đó bạn lưu file về. (Lưu ý là mỗi tài khoản ở site này chỉ được phép tải free 2 lần, cho nên các bạn cứ clone acc mà làm). Lúc lưu file nhớ chọn định dạng PDF. Nếu công cụ mà bạn sử dụng có hỗ trợ định dạng AI thì cứ dùng AI, vì ở đây nó không hỗ trợ AI nên mình dùng tạm file PDF.

Việc tiếp theo là đổi đuôi .PDF của file vừa tải về thành đuôi .AI, lí do đơn giản là Blend nó chỉ hỗ trợ định dạng này thôi.

Sau đó các bạn vào Blend, tiến hành import file .AI vừa mới đổi đuôi ở trên.

Thế là xong, Blend nó sẽ import file .AI đó vào và convert nó thành một cái Path cho bạn tùy ý đổi màu đổi size cấu xé nhai nuốt và còn có thể xử lý trực tiếp bằng code :v Ở đây mình chỉ đổi màu, xếp cho đúng chỗ, chỉnh lại opacity tí xíu. Rõ ràng là nó sẽ làm giao diện sinh động hơn nhiều.

Chỉ đơn giản thế thôi. Chúc các bạn có những ứng dụng không những chạy tốt mà còn đẹp nữa :v

YOLO \m/

Sao lưu cài đặt của emulator Windows Phone 8

Sao lưu cài đặt của emulator Windows Phone 8

Bình thường mỗi lần chúng ta debug ứng dụng Windows Phone (WP), Visual Studio sẽ khởi động emulator với cài đặt mặc định và bạn sẽ có thể dễ dàng debug những ứng dụng phổ thông, đơn giản.

Tuy nhiên nếu bạn đang làm việc với những ứng dụng yêu cầu phải cài đặt thêm, ví dụ như region, language hay keyboard, thì sự việc sẽ rắc rối hơn nhiều. Bạn sẽ phải khởi động emulator lên, chỉnh lại cài đặt, sau đó lại phải ngồi chờ cho emulator nó khởi động lại. Lâu kinh dị :v

Để khắc phục tình trạng này, rất dễ, chúng ta chỉ việc lưu lại trạng thái của emulator để xài lâu dài về sau.

Trước khi đi vào cụ thể, mình xin giải thích một tí về emulator. Kể từ SDK 8.0, emulator WP đã được tách hẳn ra thành một máy ảo chạy riêng biệt trên Hyper-V. Cụ thể, mỗi khi bạn dùng Visual Studio để debug một ứng dụng trên emulator, nó sẽ kiểm tra trong Hyper-V đã có emulator đó chưa, nếu là chưa thì sẽ tạo một máy ảo tương ứng, sau đó nó sẽ kiểm tra xem là emulator này đã có checkpoint nào chưa, nếu chưa thì nó sẽ tạo checkpoint cho máy ảo đó và những lần sau nó sẽ dùng checkpoint đó để chạy.

Máy ảo tiến hành tạo checkpoint mặc định trong lần chạy đầu tiên
Checkpoint được tạo mặc định

Vậy công việc của chúng ta đơn giản chỉ là: chạy máy ảo, cài đặt cho xả láng, rồi lưu lại thành checkpoint.

Bước 1: Chúng ta sẽ thao tác trực tiếp với máy ảo bằng Hyper-V. Đầu tiên các bạn mở Hyper-V Manager lên, sau đó chọn máy ảo ưa thích, Start rồi Connect với nó bằng các tùy chọn ở menu chuột phải. Nhớ là Start xong thì phải Connect thì mới thấy được. Nếu máy ảo bạn muốn tìm chưa có trong danh sách thì trước tiên bạn phải quay lại Visual để debug hoặc deploy một app bất kì vào máy ảo đó thì mới được.

Bước 2: Tiến hành cài đặt, vọc vạch gì đó tùy thích, miễn là các bạn vừa ý. Vì ở đây là máy ảo chạy từ Hyper-V nên sẽ không có các phím cứng giả lập như bên emulator, tuy nhiên các bạn vẫn có thể thao tác bằng các phím tắt trên bàn phím bằng các phím sau:

  • F1 – tương ứng với nút back
  • F2 – tương ứng với nút home
  • F3 – tương ứng với nút Bing
  • F7 – kích hoạt camera
  • F9/F10 – tăng giảm âm lượng
  • PageUp/PageDown  – tắt/bật bàn phím ảo, thay bằng bàn phím thật

Mình cũng edit và quyết định sẽ để như thế này

Bước 3: Sau khi đã vừa ý rồi thì tiến hành lưu trạng thái hiện tại của máy ảo thành một checkpoint bằng cách click vào nút Checkpoint ở cột bên phải của cửa sổ Hyper-V Manager.

Bước 4: Nếu để ý tí thì bạn sẽ thấy checkpoint vừa tạo sẽ trở thành một checkpoint con của checkpoint đã được tạo trước đó.

Nếu để yên vậy thì chả có tác dụng gì cả, emulator vẫn sẽ chạy với cài đặt mặc định :v vì thế bạn phải RENAME checkpoint con cho giống như checkpoint mặc định đã được tạo sẵn, sau đó XÓA checkpoint mặc định đi để checkpoint con vừa tạo trở thành checkpoint mặc định.

Thế là xong. Thử chạy emulator bằng cách debug hoặc deploy một ứng dụng bất kì, bạn sẽ thấy emulator sẽ được khởi động với cài đặt ưa thích của bạn.

Hy vọng bài viết sẽ có ích cho bạn khi làm việc với emulator :3 cái này mình học lỏm ở đây.

Chúc các bạn vui vẻ!

YOLO \m/

Sử dụng các ký tự đặc biệt trong Windows Phone

Sử dụng các ký tự đặc biệt trong Windows Phone

Chào các bạn, như chúng ta đã biết một bộ font chữ ngoài những ký tự latin bình thường ra thì tụi nó còn có một đống các kí tự não tim chim bướm đủ các thể loại. Đống kí tự này có điểm đặc biệt là bạn chẳng thể nào gõ chúng ra một cách dễ dàng. Thấy đâu đó rồi copy và paste hay đại loại thế.

Vậy phải làm sao nếu bạn muốn mang đống này vào Windows Phone (WP)?

Read More Read More

Cài đặt MessageBox xác nhận trước khi thoát

Cài đặt MessageBox xác nhận trước khi thoát

Khi lập trình nói chung và Windows Phone nói riêng, thì việc hỏi để người dùng xác nhận một cái gì đấy là điều cần thiết. Ví dụ như khi bạn làm một cái form để người dùng nhập status rồi post lên Facebook, sẽ rất khó chịu nếu người dùng lỡ tay chạm phải nút Back (mà thực tế là mình cứ bị hoài) và lại phải gõ lại status từ đầu :v

Việc này rất đơn giản, khi người dùng nhấn Back, sẽ xuất hiện 1 hộp thoại hỏi người dùng có muốn thoát không, nếu người dùng nhấp Ok thì thoát, nếu ngược lại thì không.

Bởi vì {php}MessageBox{/php} bình thường chỉ hỗ trợ một button, nhưng chúng ta lại cần đến tận 2 button, nên {php}CustomMessageBox{/php} trong bộ Windows Phone Toolkit sẽ là một lựa chọn hợp lý.

Chúng ta sẽ làm như sau:

//Override event OnBackKeyPress
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    //Không back như thông lệ
    e.Cancel = true;
    //Tạo một CustomMessageBox với các thông tin tương ứng
    CustomMessageBox myCustomMessageBox = new CustomMessageBox()
    {
        Title = "ê này",
        Content = "không muốn post gì nữa thật à?",
        LeftButtonContent = "ừ không",
        RightButtonContent = "post tiếp"
    };
    //Ra lệnh cho nó phải làm gì sau khi người dùng quyết định xong
    myCustomMessageBox.Dismissed += (sender, args) =>
    {
        switch (args.Result)
        {
            //Nếu người dùng chọn "ừ không" thì quay lại trang trước
            case CustomMessageBoxResult.LeftButton:
                NavigationService.GoBack();
                break;
        }
    };
    //Cài đặt hết rồi thì show nó ra
    myCustomMessageBox.Show();
}

Tuy nhiên, mọi chuyện hoàn toàn không hề đơn giản như vậy, rắc rối ở đây là nếu nhét nó vào sự kiện {php}OnBackKeyPress{/php}, ngay khi người dùng nhấn Back, {php}CustomMessageBox{/php} sẽ hiện ra, nhưng ngay sau đó lại biến mất luôn, hoàn toàn không để lại dấu vết gì hay có bất cứ cơ hội nào cho người dùng có thể đưa ra lựa chọn của mình.

Giải pháp ở đây khá đơn giản, đó là chỉ việc nhét hết đống code liên quan đến cái {php}CustomMessageBox{/php} đấy vào một cái {php}Dispatcher{/php} là xong :v

//Override event OnBackKeyPress
protected override void OnBackKeyPress(System.ComponentModel.CancelEventArgs e)
{
    //Không back như thông lệ
    e.Cancel = true;
    Deployment.Current.Dispatcher.BeginInvoke(() =>
    {
        //Tạo một CustomMessageBox với các thông tin tương ứng
        CustomMessageBox myCustomMessageBox = new CustomMessageBox()
        {
            Title = "ê này",
            Content = "không muốn post gì nữa thật à?",
            LeftButtonContent = "ừ không",
            RightButtonContent = "post tiếp"
        };
        //Ra lệnh cho nó phải làm gì sau khi người dùng quyết định xong
        myCustomMessageBox.Dismissed += (sender, args) =>
        {
            switch (args.Result)
            {
                    //Nếu người dùng chọn "ừ không" thì quay lại trang trước
                case CustomMessageBoxResult.LeftButton:
                    NavigationService.GoBack();
                    break;
            }
        };
        //Cài đặt hết rồi thì show nó ra
        myCustomMessageBox.Show();
    });
}

Và bây giờ thì mọi thứ sẽ hoạt động ngon lành  cho các bạn :v

Chúc các bạn thành công :3

Dzô lô \m/

Cài đặt nhanh một bộ chuyển đổi các giá trị boolean

Cài đặt nhanh một bộ chuyển đổi các giá trị boolean

Chào các bạn, gần đây mình gặp một vấn đề như thế này: mình muốn convert một thuộc tính kiểu bool ra nhiều kiểu giá trị, để bind lên giao diện. Mình tiến hành bằng việc dùng các converter như thông thường, nhưng vấn đề là lượng converter mình làm là khá nhiều (tầm 15 cái), ăn ở tốt thế nào mà mò được post này :3 nên mang về share các bạn.

Vấn đề rất đơn giản, ví dụ bạn có một class thế này:

public class MyHater
{
    public string Name { get; set; } 
    public bool Gender { get; set; } //1-Male, 2-Female
}

Ở giao diện chính của chương trình, bạn muốn nếu là nam thì ghi rõ là “Male” và tô xanh, trong khi là nữ thì ghi rõ “Female” và tô đỏ. Việc này có thể dễ dàng thực hiện bằng cách cài đặt 2 class với interface {php}IValueConverter{/php}, ví dụ như {php}GenderToStringConverter{/php} và {php}GenderToColorConverter{/php}.

public class GenderToStringConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value ? "Male" : "Female";
    }
}

public class GenderToColorConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value ? new SolidColorBrush(Color.FromArgb(255,0,0,255)) : new SolidColorBrush(Color.FromArgb(255,255,0,0));
    }
}

Đơn giản phải không, nhưng mà ở đây mới chỉ có 2 converter, giả sử bạn muốn cài 10 hay thậm chí là 20 cái thì sao :v nhiều vờ lờ luôn đúng không? Có thể bạn sẽ copy và paste, nhưng mà làm như thế lại rất tốn thời gian và khó để quản lý code, trong khi mỗi class chỉ khác nhau 2 giá trị mà bạn return.

Vậy nên chúng ta sẽ đi đường khác. Đầu tiên chúng ta sẽ cài đặt một class với interface IValueConverter, điểm đặc biệt của class này là nó sẽ bảo đảm trả về một kiểu T, đồng thời nó sẽ có thêm 2 thuộc tính kiểu T: TrueValueFalseValue, một cái sẽ trả về nếu bool là true, cái còn lại thì ngược lại. Cụ thể:

public class BoolToValueConverter<T> : IValueConverter
{
    //Cái này sẽ được trả về nếu bool là false
    public T FalseValue { get; set; }
    //Cái này thì ngược lại
    public T TrueValue { get; set; }

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        if (value == null)
            return FalseValue;
        else
            return (bool)value ? TrueValue : FalseValue;
    }
}

Đến bao giờ cần dùng thì chỉ việc kế thừa và chỉ rõ bạn muốn convert giá trị bool thành kiểu gì thôi. Chẳng hạn:

public class BoolToVisibilityConverter : BoolToValueConverter<Visibility> {}
public class BoolToStringConverter : BoolToValueConverter<string> {}
public class BoolToColorConverter : BoolToValueConverter<Colors> {}
public class BoolToAnythingConverter : BoolToValueConverter<object> {}

Xong chưa? Vẫn chưa, còn một lưu ý nhỏ nữa, bạn có nhớ lúc đầu chúng ta khai báo 2 giá trị trả về kiểu T không? Để mọi thứ chạy ngon nghẻ thì bạn phải cho nó biết 2 giá trị nó sẽ trả về đó là như thế nào, cụ thể là bạn phải khai báo trong xaml trước khi dùng như sau:

<converters:BoolToVisibilityConverter x:Name="BoolToVisibility" TrueValue="Visible" FalseValue="Collapsed"/>
<converters:BoolToStringConverter x:Name="BoolToString" TrueValue="Male" FalseValue="Female"/>
<converters:BoolToColorConverter x:Name="BoolToColor" TrueValue="Red" FalseValue="Blue"/>

Thế là xong, bây giờ chỉ việc dùng như một converter bình thường.

Chúc các bạn vui vẻ. Dô lô \m/

Highlight 1 đoạn text trong control TextBlock

Highlight 1 đoạn text trong control TextBlock

Lập trình với Silverlight, dự là sẽ có lúc bạn phải highlight một hoặc một số đoạn text tron control TextBlock (như khi cài đặt tính năng search chẳng hạn).

Để làm điều này có thể có nhiều cách, ví dụ như nhét vào một StackPanel, trong các StackPanel đó thì lại add thêm nhiều TextBlock nhỏ, mỗi TextBlock chứa đoạn text với màu tương ứng. Cách này hoàn toàn khả dĩ, tuy nhiên nếu muốn highlight n đoạn text thì nhiều khả năng bạn sẽ phải tạo đến 2n+1 TextBlock :v siêu rườm rà.

Thật ra công việc của bạn có thể đơn giản hơn bằng việc sử dụng class {php}Run{/php} nằm trong namespace {php}System.Windows.Documents{/php}. Ví dụ mình dùng dưới đây là để highlight 1 đoạn text, muốn highlight nhiều đoạn thì cũng chỉ việc làm tương tự.

/// <summary>
/// Dùng để highlight 1 đoạn text
/// </summary>
/// <param name="textBlock">Control TextBlock có đoạn text cần highlight</param>
/// <param name="text">Đoạn text hiển thị trong TextBlock</param>
/// <param name="toSet">Đoạn text cần highlight</param>
private void SetTextBlock(TextBlock textBlock, string text, string toSet)
{
    //Trước tiên phải xóa nội dung của TextBlock
    textBlock.Inlines.Clear();

    int selectedIndex = text.IndexOf(toSet);

    //Tạo một con Run, con Run này sẽ là đoạn text nằm trước đoạn cần highlight
    Run before = new Run();
    before.Text = text.Substring(0, selectedIndex);

    //Tạo con Run thứ 2, con Run này chứa đoạn text cần highlight
    Run toSetRun = new Run();
    toSetRun.Text = toSet;
    //Trang trí cho con Run này theo ý muốn của bạn
    toSetRun.Foreground = new SolidColorBrush(Colors.Orange);
    toSetRun.FontWeight = FontWeights.ExtraBold;

    //Tạo con Run thứ 3, con Run này chứa đoạn text nằm phía sau đoạn cần highlight
    Run after = new Run();
    after.Text = text.Substring(selectedIndex + toSet.Length);

    //Cuối cùng là add hết mấy con Run vừa tạo vào TextBlock
    textBlock.Inlines.Add(before);
    textBlock.Inlines.Add(toSetRun);
    textBlock.Inlines.Add(after);
}

Thử áp dụng lên một ví dụ đơn giản, bạn sẽ có được kết quả đại loại như thế này:

Chỉ đơn giản vậy thôi, chúc các bạn vui vẻ! YOLO :3

Publish ứng dụng Windows Phone dưới dạng beta

Publish ứng dụng Windows Phone dưới dạng beta

1. Publish dưới dạng beta là gì?
Publish dưới dạng beta là publish dưới dạng beta thôi, có thế mà cũng hỏi :v

2. Publish dưới dạng beta khác với publish bình thường như thế nào?
Theo quy trình bình thường, mỗi khi bạn submit một ứng dụng lên store, ứng dụng sẽ đi qua hàng loạt các bài test trước khi bạn biết được kết quả là ứng dụng liệu đã đạt chuẩn hay chưa. Quá trình này thường tốn của chúng ta từ 3-5 ngày.
Publish dưới dạng beta thì không như vậy, ứng dụng chúng ta sẽ không được test bởi đội ngũ tester của store, mà sẽ là những tester do chúng ta quyết định. Thời gian từ khi chúng ta submit ứng dụng thành công đến khi ứng dụng có mặt trên store chỉ là vài phút.

3. Sướng vậy, vậy sao không publish ứng dụng theo kiểu beta luôn cho rồi?
Cái đó là tùy bạn :v vì chỉ những ai được chỉ định mới có thể tải ứng dụng về từ store, số lượng này được giới hạn là 10k người. Và thêm một điều nữa là những ứng dụng được publish dưới dạng beta chỉ có thể có mặt trên store trong 90 ngày.

4. Thế tại sao lại phải dùng tính năng beta testing?
Cái lợi lớn nhất là tiết kiệm thời gian cho bạn. Vì không phải cứ test ngon lành ứng dụng nào thì ứng dụng đó sẽ pass. Có một số lỗi chỉ xuất hiện KHI VÀ CHỈ KHI ứng dụng được tải trực tiếp về từ store. Ví dụ bạn đang tham gia một cuộc thi, thì mỗi lần ứng dụng của bạn bị fail là một lần bất lợi cho bạn.

5. Còn gì cần lưu ý nữa không?
Tính năng mới chỉ có mặt trên Windows Phone Store, Windows Store thì vẫn chưa. Thêm nữa là tổng lượng download dạng beta cũng được tính chung vào với tổng lượt download của tài khoản của bạn.

6. Vậy cụ thể các bước để upload dưới dạng beta là như nào?
Rất dễ, đầu tiên bạn đăng nhập vào tài khoản developer của bạn, tiến hành Submit App như bình thường

Tiếp theo bạn cũng tiến hành cập nhật thông tin của ứng dụng bằng cách chọn mục App info

Đây mới là bước cần lưu ý, sau khi nhập xong thông tin của ứng dụng, bạn kéo xuống gần cuối trang sẽ thấy mục More options, bạn nhấp vào, ở tùy chọn Distribution channels, bạn chọn Beta, đồng thời điền email của những tester được chỉ định, các email phải cách nhau bằng dấu chấm phẩy (‘;’). Lưu ý là chỉ device nào được gán với các email này thì mới xem và tải được ứng dụng của bạn từ store.

Các bước còn lại các bạn cứ tiến hành như bình thường. Sau khi submit thành công, chờ một vài phút (thường là như vậy, cá biệt có lần vì store bị nghẽn nên phải gần 6 tiếng sau thì ứng dụng của mình mới xuất hiện) là ứng dụng của bạn đã có mặt trong dashboard, từ đây bạn có thể lấy link và gửi cho các tester.

Vậy là xong, cách làm trên đây sẽ giúp bạn giảm thiểu tối đa thời gian trong việc submit ứng dụng lên store, tuy nhiên không có giải pháp nào là triệt để hoàn toàn, vậy nên để đỡ tốn thời gian, theo mình thì chúng ta vẫn nên {php}try{/php} – {php}throw{/php} – {php}catch{/php} kỹ càng và thường xuyên.

Chúc các bạn vui vẻ! YOLO \m/