Add a Window Control to a Silverlight for Windows Embedded Application (Windows Embedded CE 6.0)
1/6/2010
To add a window control you created for an earlier version of Windows Embedded CE to your Silverlight for Windows Embedded application, first create an IXRWin32Control, and then swap the handle of the IXRWin32Control with the handle to the window control. You can then configure the sizing and positioning of the IXRWin32Control.
Prerequisites
- You have a window control from an earlier version of Windows Embedded CE that you want to reuse in Silverlight. You created your window control by using CreateWindow or CreateWindowEx, and the window control has its own WndProc.
- You have an OS design that includes SYSGEN_XAML_RUNTIME. **
For more information, see Creating an OS Design with the Windows Embedded CE OS Design Wizard. - You have a Silverlight application. For more information, see Create a Silverlight for Windows Embedded Application.
Step 1 Create a Subproject for the Application
Create a subproject for the Silverlight application that will reuse your window control. In the .cpp source file, include the XamlRuntime.h header file as follows:
#include "XamlRuntime.h"
For more information, see Creating a New Subproject.
Step 2 Create an IXRWin32Control Object to Represent the Window Control
You have two options:
- You can define the empty Win32 control in the source XAML, or
- If you cannot modify the source XAML, you can create the empty Win32 control in C++.
To define a placeholder Win32 control in XAML
In pre-existing code, locate the C++ code that creates the window control and find its class name.
In Microsoft Visual Studio 2005, open the source XAML file.
In the source XAML file, include the XAML namespace declaration for Win32 controls in the root element.
xmlns:xr="clr-namespace:EmbeddedXamlRuntime"
In the source XAML file, define a XAML element that has the xr namespace prefix and that specifies the x:Name attribute and on-screen position.
<xr:Win32Control x:Name="Win32CtlSample" xr:ClassName="ClassNameSample" Height="50" Width="50" Margin="8,8,93,0" HorizontalAlignment="Left" VerticalAlignment="Top" > <xr:Win32Control.RenderTransform> <TranslateTransform x:Name="Win32ControlTranslateTransform" X="0" Y="0" /> </xr:Win32Control.RenderTransform> </xr:Win32Control>
(Optional) Specify the class name by adding a value for the ClassName attribute.
- If you specify the ClassName attribute in the XAML file and the corresponding WndClass is already registered in C++, a Win32 window handle will be created after you parse the XAML, and it will be hooked to the WndProc that you provided with class name.
- If you do not specify the ClassName attribute in the XAML file, the visual tree will contain only an empty IXRWin32Control object that is a placeholder control and represents any empty UI region in the visual layout. You must then call IXRWin32Control::SetHandle to set it to the real handle from somewhere else in your code.
(Optional) Define an animation storyboard in the resources that belong to the panel element. This storyboard animates a property that you define for the Win32 control. The property must be a layout-related property inherited from a parent class, such as X or Height. In XAML, you specify the property in the Storyboard.TargetProperty attached property. For more information about how to define this element in the source XAML for your application, see this Microsoft Web site.
When the C++ application parses the XAML markup and loads it into an element tree, it also parses the Win32 control XAML element into an IXRWin32Control object.
To create a placeholder Win32 control in C++
In pre-existing code, locate the C++ code that creates the window control and then find the class name for the window control.
In Platform Builder, open your Silverlight-based application.
In your application code, create an IXRWin32Control object, locate the panel object in the visual tree, and then add the IXRWin32Control object to the panel.
void CreateControl(IXRApplication* pApplication) { IXRWin32Control *pIWin32Ctl = NULL; pApplication->CreateObject(IID_IXRWin32Control, &pIWin32Ctl); }
In your application code, set the properties on the object you created by using the Set methods inherited from IXRControl. You must specify the class name defined for the standard window control in the method IXRWin32Control::SetClassName.
void SetProperties(IXRWin32Control* pIWin32Ctl) { pIWin32Ctl->SetClassName(L"StandardControlClass"); pIWin32Ctl->SetName(L"Win32CtlSample"); pIWin32Ctl->SetHeight(80); pIWin32Ctl->SetWidth(200); }
Add the new Win32 control to the IXRUIElementCollection of a panel object in the visual tree. You can do this by obtaining a pointer to the collection from IXRPanel::GetChildren.
void AddToCollection(IXRStackPanel* pPanel, IXRWin32Control* pIWin32Control) { IXRUIElementCollection *pChildCollection; pPanel->GetChildren(&pChildCollection); pChildCollection->Add(&pIWin32Control, NULL); }
After you create the control, set additional supported properties on the IXRWin32Control.
Step 3 Integrate the Window Control into Your Application
In your Silverlight application, swap the standard window control handle with a Silverlight window control handle, so that your IXRWin32Control object is associated with the standard window control.
Note
Do not implement event-handling code for the TAB event in the WndProc for the Win32 control. When the window control receives focus, GWES routes messages and events to the WndProc that you created for the standard window control, instead of to the default WndProc for the visual host window. To give focus back to the visual host window and to navigate away from the window control, the user must press the TAB key or another navigation key.
To integrate a standard window control into your application
In your code, find the variable that represents the window handle that the CreateWindow or CreateWindowEx function returns. For example,
g_hwndDlg
.Initialize Silverlight and parse the source XAML file into an object tree.
Obtain a pointer to the new placeholder IXRWin32Control object in the object tree, as follows:
To locate a placeholder Win32 control that you added in C++, obtain a pointer to the IXRWin32Control object you created in Step 2.
To locate a placeholder Win32 control that you parsed from XAML, call IXRFrameworkElement::FindName and supply the value that you specified x:Name. For more information, see Step 2.
For example:IXRWin32ControlPtr pIWin32Ctl; pRoot->FindName(L"Win32CtlSample", &pIWin32Ctl));
Swap the default handle to the IXRWin32Control instance with the handle to your window control. You can use the HWND variable that the CreateWindow or CreateWindowEx method returned. To do this, call IXRWin32Control::SetHandle.
pIWin32Ctl->SetHandle(g_hwndDlg, false); ShowWindow(HostWindow, SW_SHOW); UpdateWindow(HostWindow);
Your window control is now represented in the visual tree and is integrated with the on-screen layout of peer controls in the window.
Step 4 Build the Application and the OS Design
To build subproject code, in Platform Builder, go to Solution Explorer, and then right-click <MySubProject name> and click Build.**
To build an OS design, see Building a Run-Time Image.
Example
Description
The following example code defines a Win32 control in a Canvas element in Microsoft Silverlight 2 XAML. It also defines an animation storyboard that animates the X property of the TranslateTransform element that belongs to the Win32 control.
Code
<Canvas
xmlns="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xr="clr-namespace:EmbeddedXamlRuntime"
Width="1000" Height="300">
<Canvas.Resources>
<Storyboard x:Name="AnimationTarget">
<DoubleAnimationUsingKeyFrames
Storyboard.TargetName="Win32ControlTranslateTransform"
Storyboard.TargetProperty="X"
Duration="0:0:10">
<LinearDoubleKeyFrame Value="500" KeyTime="0:0:10" />
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</Canvas.Resources>
<xr:Win32Control x:Name="Win32CtlSample" xr:ClassName="ClassNameSample" Height="50" Width="50" >
<xr:Win32Control.RenderTransform>
<TranslateTransform x:Name="Win32ControlTranslateTransform" X="0" Y="0" />
</xr:Win32Control.RenderTransform>
</xr:Win32Control>
</Canvas>
Comments
After the C++ application parses this example XAML markup and loads it into an element tree, you can locate the empty Win32 control by calling IXRFrameworkElement::FindName and then using FindName to search for "Win32CtlSample".
Example
Description
The following example code shows how to find a placeholder Win32 control in the visual tree and swap its handle for a new one so that it represents a new window control.
In this example code, the source XAML markup in win32ctl.xaml predefines the placeholder Win32 control and assigns it the x:Name "MyWindowControl".
Important
For readability, the following code example does not contain security checking or error handling. Do not use the following code in a production environment.
For information about the programming elements used in this example code, see XRPtr<Interface>, IXRApplication, IXRVisualHost, WNDCLASS, and CreateWindow.
Code
#include <windows.h>
#include <XamlRuntime.h>
#include <XRPtr.h>
AddWindowControl(IXRApplication* pApplication, HINSTANCE hInstance, WNDPROC lpSampleWndProc)
{
XRXamlSource Source;
Source.SetFile(L"win32ctl.xaml");
XRWindowCreateParams Params = {WS_POPUP | WS_BORDER, NULL, 0, 200, 200, 300, 300, NULL, NULL, 1, NULL};
IXRVisualHostPtr pActiveHost;
IXRFrameworkElementPtr pRootElement;
IXRWin32ControlPtr pIWin32Ctl;
pApplication->CreateHostFromXaml(&Source, &Params, &pActiveHost);
HWND HostWindow = NULL;
HWND NewHandle = NULL;
// obtain the container window handle and a pointer
//to the visual root
pActiveHost->GetContainerHWND(&HostWindow);
pActiveHost->GetRootElement(&pRootElement);
// traverse the visual tree and
// locate a predefined Win32Control object
pRootElement->FindName(L"Win32CtlSample", &pIWin32Ctl);
WNDCLASS WndClass1 = {0};
LPCTSTR c_ClassName1 = L"Class Name";
WndClass1.hInstance = hInstance;
WndClass1.lpszClassName = c_ClassName1;
WndClass1.lpfnWndProc = lpSampleWndProc;
WndClass1.cbWndExtra = sizeof(DWORD);
WndClass1.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
RegisterClass(&WndClass1);
NewHandle = CreateWindow(
c_ClassName1,
L"New Window",
WS_THICKFRAME | WS_HSCROLL | WS_VSCROLL | WS_OVERLAPPED,
0, 0, // position will be determined at runtime
// by the layout system
0, 0, // size value is not used
NULL,
NULL,
hInstance,
NULL
);
// swap the old handle for the new handle
pIWin32Ctl->SetHandle(NewHandle, false);
if (!IsChild(HostWindow, NewHandle))
{
goto Error;
}
// activate the visual host window and repaint the changed portion
ShowWindow(HostWindow, SW_SHOW);
UpdateWindow(HostWindow);
UINT* exitCode = 1;
pApplication->StartProcessing(&exitCode);
Error:
if (pActiveHost)
{
pActiveHost->DestroyWindow();
pActiveHost->Release();
pActiveHost = NULL;
}
if (pApplication)
{
pApplication->Release();
pApplication = NULL;
}
if (pRootElement)
{
pRootElement->Release();
}
if (IsXRInitialized)
{
XamlRuntimeUninitialize();
}
return 0;
}
Comments
To run this example code, you must provide the HINSTANCE handle to the application instance from the WinMain routine in your application, a pointer to the window procedure (WNDPROC) you have created for the Win32 control, and the IXRApplication instance.
See Also
Tasks
Create a Silverlight for Windows Embedded Application