Silverlight for Windows Embedded: how to communicate imagesource Dependency Property between xaml and code-behind

378 views Asked by At

I am working on a Silverlight for Windows Embedded project. I defined a custom user control which consists of an image control. I want to specify different image source in xaml for different instance of the custom control. So I define a Dependency Property "MyImage" in the custom control.

In the Blend C# code-behind: public UserControl1() { InitializeComponent(); ItemImage.DataContext = this; }

    public ImageSource MyImage
    {
        get { return (ImageSource)GetValue(MyImageProperty); }
        set { SetValue(MyImageProperty, value); }
    }

    public static readonly DependencyProperty MyImageProperty =
        DependencyProperty.Register("MyImage", typeof(ImageSource), typeof(UserControl1), null);

In UserControl.xaml I bind the image control Source property to MyImage:

<Image x:Name="ItemImage" Margin="0,0,90,0" Source="{Binding MyImage}"/>

So when I use the custom control I can do this in xaml:

<local:UserControl1 HorizontalAlignment="Left" Margin="94,117,0,0" Width="196" Height="85" VerticalAlignment="Top" MyImage="img1.png"/>
<local:UserControl1 HorizontalAlignment="Left" Margin="94,217,0,0" Width="196" Height="85" VerticalAlignment="Top" MyImage="img2.png"/>

Testing in Blend is ok. I can see the two images shown in the two custom control instance.

Then coming to SWE C++ code-behind, I redefined and register the Dependency Property in UserControl1.cpp:

XRDependencyPropertyMetaData dpmImage = XRDependencyPropertyMetaData();
dpmImage.Size = sizeof(IXRImageSource);
dpmImage.pfnPropertyChangeNotification = ImagePropertyChanged;
dpmImage.pfnTypeConverter = ConvertNameTypeConverter;
dpmImage.pfnEnumerableCreation = NULL;

XRValue defImage;
defImage.vType = VTYPE_OBJECT;
defImage.pObjectVal = NULL;
dpmImage.DefaultValue = defImage;

hr = pApplication->RegisterDependencyProperty(L"MyImage", VTYPE_OBJECT, ControlID(), &dpmImage, &m_dpMyImageID);

void UserControl1::ImagePropertyChanged( __in IXRDependencyObject* pControl, __in XRValue* pOldValue, __in XRValue* pNewValue )
{......}
HRESULT UserControl1::ConvertNameTypeConverter( XRValue *pValIn, XRValue *pValOut )
{......}

The compilation and execution is successful, just that I don't see images being displayed in the two controls.

When debugging, I can see the ConvertNameTypeConverter callback is first invoked. I can see the image file name is stored in pValIn as a string, which is inline with what MSDN documentation describes: When XAML for Windows Embedded calls this function in the parsing phase, pValIn will always be a string.

Next the ImagePropertyChanged callback is invoked, and I can see pNewValue contains the values I set to pValOut in ConvertNameTypeConverter().

My question is, am I doing the correct way? If I can only get a string for the image file name, how can I get the image binary from the string?

Is there a way to directly transfer the image binary from xaml to C++ code-behind and display directly?

Thanks!

2

There are 2 answers

0
zhangwei On BEST ANSWER

Problem solved. But I think my solution looks like just a workaround. In the callback I tried to use LoadImageFromResource to load the image binary from resource file:

void UserControl1::ImagePropertyChanged( __in IXRDependencyObject* pControl, __in XRValue* pOldValue, __in XRValue* pNewValue )
{
    IWICBitmap *pImage = NULL;
    IXRBitmapImagePtr pBitmap;
    GetXRApplicationInstance(&pApplication);
    pApplication->LoadImageFromResource(App::GetHInstance(), pNewValue->bstrStringVal, L"XAML_RESOURCE", &pImage);

    pApplication->CreateObject(&pBitmap);
    pBitmap->SetSource(pImage);
    pApplication->Release();

    UserControl1 *tempObj;
    pControl->QueryInterface(__uuidof(UserControl1), (void**)&tempObj);
    tempObj->m_pItemImage->SetSource((IXRImageSource*)pBitmap);
}

However the 2nd argument pResourceName expects a resource ID automatically generated by XRPack in .rc file. For e.g.:

103 XAML_RESOURCE DISCARDABLE "..\\..\\..\\..\\Expression\\Blend_3\\Projects\\WindowsEmbeddedSilverlightApplication1\\WindowsEmbeddedSilverlightApplication1\\img1.png"

Then pResourceName should be MAKEINTRESOURCE(103).

Since the ID is automatically assigned by XRPack, there is no way for me to know the image name to ID mapping dynamically.

So I write a perl script to process .rc file and convert the above line into:

img1.png XAML_RESOURCE DISCARDABLE "..\\..\\..\\..\\Expression\\Blend_3\\Projects\\WindowsEmbeddedSilverlightApplication1\\WindowsEmbeddedSilverlightApplication1\\img1.png"

In VS I configure the script to run after XRPack generates .rc file and before compilation starts. That is how

LoadImageFromResource(App::GetHInstance(), pNewValue->bstrStringVal, L"XAML_RESOURCE", &pImage);

will work.

0
Mariusz On

You can define IDs which are generated by XRPack. To do that, define in your XAML Code:

<Image xrpack:Resource="Source:902(IDR_SETTINGS)" Margin="0" Source="Image.png"/>

If you are using Expression Blend, you will probably also have to define namespace for "xrpack". To do that, define in UserControl:

mc:Ignorable="d xrpack"
xmlns:xrpack="http://schemas.microsoft.com/windowsembedded/silverlight/packaging"

In C++ code you can now use LoadImageFromResource method:

LoadImageFromResource(App::GetHInstance(), MAKEINTRESOURCE(IDR_SETTINGS), L"XAML_RESOURCE", &pImage);