Trong môi trường Windows Embedded CE 7.0, quy trình khởi động của một ứng dụng Silverlight (dựa trên XAML) tuân theo một chuỗi lời gọi nhất định, được minh họa qua stack trace sau:
SWEClock.exe!MainPage::OnLoaded(IXRDependencyObject* pRoot = 0x00047840) Line: 37, Offset: 0x24 C++
SWEClock.exe!XRCustomUserControlImpl<MainPage,IXRCustomUserControl>::Create(IXRDependencyObject* pExistingDependencyObject = 0x0004782c, IXRDependencyObject** ppNewDp = 0x0003fbf4) Line: 568, Offset: 0x188 C++
0x40158c30
0x40158e98
0x4015c850
>SWEClock.exe!IXRApplication::CreateObject<IXRCustomUserControl>(_GUID& riid = {...}, IXRCustomUserControl** ppObject = 0x0003fcb0) Line: 3112, Offset: 0x3c C++
SWEClock.exe!App::CreateHost(XRWindowCreateParams* pCreateParams = 0x0003fd00) Line: 112, Offset: 0x54 C++
SWEClock.exe!App::Initialize(HINSTANCE__* hInstance = 0x064c005e) Line: 146, Offset: 0x148 C++
SWEClock.exe!WinMain(HINSTANCE__* hInstance = 0x064c005e, HINSTANCE__* __formal = 0x00000000, wchar_t* __formal = 0x0003fe88, int __formal = 0x00000005) Line: 32, Offset: 0x6c C++
SWEClock.exe!WinMainCRTStartupHelpANCE__* hInstaner(HINSTce = 0x00000054, HINSTANCE__* hInstancePrev = 0x00000000, unsigned short* lpszCmdLine = 0x00000000, int nCmdShow = 0x00070005) Line: 71, Offset: 0x40 C
Sau khi thư viện phân tích XAML được gọi, luồng điều khiển quay trở lại mã ứng dụng thông qua hàm OnLoaded(). Điều này có nghĩa là tên hàm OnLoaded() là cố định và không thể thay đổi.
Các định nghĩa liên quan:
IXRApplication::CreateObjectđược định nghĩa trongx:\Program Files\Windows CE Tools\SDKs\HSW_T9_SDK\Include\Armv4i\xamlruntime.hXRCustomUserControlImpl<MainPage,IXRCustomUserControl>::Createđược định nghĩa trongx:\Program Files\Windows CE Tools\SDKs\HSW_T9_SDK\Include\Armv4i\xrcustomcontrol.h
Trong MainPage::OnLoaded(), quá trình phân tích file XAML chính thức bắt đầu. Dựa trên nội dung file XAML, các biến phần tử tương ứng được khai báo. Để biết thư viện XAML hỗ trợ những phần tử nào, bạn có thể tham khảo file header x:\Program Files\Windows CE Tools\SDKs\HSW_T9_SDK\Include\Armv4i\xrptr.h, phần cuối có chứa các định nghĩa tương tự như sau:
1 #define XR_SMARTPTR(x) typedef XRPtr< x > x##Ptr
2
3 XR_SMARTPTR(IXRArcSegment);
4 XR_SMARTPTR(IXRBeginStoryboard);
5 XR_SMARTPTR(IXRBezierSegment);
6 XR_SMARTPTR(IXRBitmapCache);
7 XR_SMARTPTR(IXRBitmapImage);
8 XR_SMARTPTR(IXRBorder);
9 XR_SMARTPTR(IXRBrush);
10 XR_SMARTPTR(IXRCanvas);
Bạn cũng có thể gán sự kiện cho các phần tử, ví dụ như sự kiện tải (loaded), nhấp chuột (click), v.v. Thông thường, nếu form cần xử lý đặc biệt khi tải, bạn sẽ định nghĩa sự kiện tải và hoàn thành các công việc chuẩn bị trong hàm xử lý sự kiện.
(1) Xử lý sự kiện Layout Loaded
Giả sử Canvas là phần tử gốc (Root Element), bạn có thể định nghĩa như sau: IXRCanvasPtr m_pLayoutRoot;
1 FindName(L"LayoutRoot", &m_pLayoutRoot);
2 if (m_pLayoutRoot)
3 {
4 m_pLayoutRoot->AddLoadedEventHandler(CreateDelegate(this, &MainPage::Canvas_Loaded));
5 }
6
7 // ============================================================================
8 // Canvas_Loaded
9 //
10 // Description: Event handler implementation
11 // Lưu ý: Sự kiện Loaded="Canvas_Loaded" trong XAML không bắt buộc phải khớp với tên hàm này. Bạn có thể đổi thành Loaded="Canvas_Loaded_2" và chương trình vẫn chạy bình thường.
12 // Parameters: pSender - Dependency object gây ra sự kiện.
13 // pArgs - Đối số của sự kiện.
14 // ============================================================================
15 HRESULT MainPage::Canvas_Loaded (IXRDependencyObject* pSender, XRRoutedEventArgs* pArgs)
16 {
17 // Xử lý logic tại đây
18 }
(2) Thêm xử lý sự kiện nút bấm
Bạn có thể truy cập vào nút bấm thông qua thuộc tính Name được khai báo trong Expression Blend (XAML) hoặc chỉnh sửa trực tiếp file XAML. Sử dụng kiểu phần tử XAML được định nghĩa trong file x:\Program Files\Windows CE Tools\SDKs\HSW_T9_SDK\Include\Armv4i\xrptr.h, ví dụ:
1 IXRButtonBasePtr MyBtn;
2 if (FAILED(retCode=root->FindName(TEXT("MyButton"), &MyBtn)))
3 return -1;
Để nhận thông báo khi người dùng nhấp vào nút, bạn cần cung cấp một delegate (khái niệm quen thuộc với lập trình viên C#). Trong C++, delegate ở đây là một con trỏ trỏ tới phương thức của một thể hiện (instance) của lớp C++ với prototype được xác định trước.
Bạn có thể khai báo một lớp C++ đơn giản trong file .cpp và triển khai delegate cho sự kiện nhấp chuột:
1 class BtnEventHandler
2 {
3 public:
4 HRESULT OnClick(IXRDependencyObject* source, XRMouseButtonEventArgs* args)
5 {
6 MessageBox(NULL, TEXT("Click!"), TEXT("Silverlight for Windows Embedded test"), MB_OK);
7 return S_OK;
8 }
9 };
Khi nút được nhấp, event handler chỉ đơn giản hiển thị một hộp thoại thông báo. Như bạn thấy, event handler có hai tham số: một con trỏ tới đối tượng gây ra sự kiện (nút bấm) và một con trỏ tới cấu trúc chứa tham số sự kiện.
Để kết nối event handler với nút bấm, bạn cần tạo một đối tượng delegate:
1 BtnEventHandler handler;
2 IXRDelegate<XRMouseButtonEventArgs>* clickDelegate;
3 if (FAILED(retCode=CreateDelegate(&handler, &BtnEventHandler::OnClick, &clickDelegate)))
4 return -1;
5 if (FAILED(retCode=MyBtn->AddClickEventHandler(clickDelegate)))
6 return -1;
Sau đó, event handler đã được gắn vào nút. Bây giờ chỉ cần chờ người dùng nhấp vào nút để hiển thị UI.
Lưu ý rằng con trỏ tới đối tượng delegate không phải là smart pointer, vì vậy bạn cần giải phóng nó một cách tường minh:
1 clickDelegate->Release();