Home > .NET, C#, Universal Windows Platform > Pay attention to .NET Native when using Reflection (MVVM scenario)

Pay attention to .NET Native when using Reflection (MVVM scenario)

22/02/2016

Among the other things, .NET Native tries to reduce the app size by analyzing the code and striping out unused .NET objects. This approach works very well, but we need to pay attention when we you work with Reflection, because in this case we must explicitly tell to .NET Native which elements are available for it.

A particular scenario occurs if we’re following the MVVM pattern and we have a classic app with a GridView or a ListView and we want to invoke a command when the user clicks an item, passing the item itself to the command. With the Universal Windows Platform, this task can be accomplished using an EventTriggerBehavoir form XamlBehavoirs along with an InvokeCommandAction and an InputConverter:

<GridView IsItemClickEnabled="True" ItemsSource="{Binding People}">
    <GridView.ItemTemplate>
        <DataTemplate>
            ...
        </DataTemplate>
    </GridView.ItemTemplate>

    <Interactivity:Interaction.Behaviors>
        <Interactions:EventTriggerBehavior EventName="ItemClick">
            <Interactions:InvokeCommandAction 
                Command="{Binding ItemSelectedCommand}" 
                InputConverter="{StaticResource EventArgsConverter}" 
                InputConverterParameter="ClickedItem" />
        </Interactions:EventTriggerBehavior>
    </Interactivity:Interaction.Behaviors>
</GridView>

At lines 9-14 we use an EventTriggerBehavior to catch the ItemClick event of the GridView and execute in response the ItemSelectedCommand action of the ViewModel. Thanks to InputConverter and InputConverterParamter (lines 12-13), this action automatically receives the clicked item as argument:

public sealed class EventArgsConverter : IValueConverter
{
    public object Convert(object value, Type targetType, object parameter, 
        string language)
    {
        if (value != null)
        {
            var propertyPath = parameter as string;
            if (!string.IsNullOrWhiteSpace(propertyPath))
            {
                var propertyPathParts = propertyPath.Split('.');
                object propertyValue = value;
                foreach (var propertyPathPart in propertyPathParts)
                {
                    var propInfo = propertyValue.GetType().GetTypeInfo().
                        GetDeclaredProperty(propertyPathPart);

                    propertyValue = propInfo.GetValue(propertyValue);
                }

                return propertyValue;
            }
        }

        return value;
    }

    public object ConvertBack(object value, Type targetType, object parameter, 
        string language)
    {
        throw new NotImplementedException();
    }
}

This Converter extracts the property name of the event argument that is passed as parameter (line 8, in this case ClickedItem) and then uses Reflection (lines 15-18) to get the actual value that will be received by the command.

This code works without problem in Debug mode, but when we switch to Release, enabling the .NET Native toolchain (that is required for app submission), if we click an item on the grid we’ll get a runtime error like the following one:

Unhandled exception at 0x77026D7E (combase.dll)

This occurs because the .NET Native toolchain has removed the ItemClickEventArgs class from the compiled code, as it hasn’t found any reference to it in the code, because it is accessed only at runtime through Reflection.

So, as said at the beginning we need to tell to .NET Native to keep this type during compilation. Let’s open the file Default.rd.xml inside the project Properties folder: it contains the Runtime Directives for .NET Native. All that we need is to add a declaration for the ItemClickEventArgs type:

<Directives xmlns="http://schemas.microsoft.com/netfx/2013/01/metadata">
    <Application>
        <!--
          An Assembly element with Name="*Application*" applies to all 
          assemblies in the application package. The asterisks are not 
          wildcards.
        -->
        
        <Assembly Name="*Application*" Dynamic="Required All" />

        <!-- Add your application specific runtime directives here. -->
        <Type Name="Windows.UI.Xaml.Controls.ItemClickEventArgs" 
              Dynamic="Required Public" />

    </Application>
</Directives>

At lines 12-13 we have specified that we want to keep the ItemClickEventArgs type in compilation, even if it isn’t statically referenced in the code. Now we can compile the app in Release mode again: this time everything will work as expected.

We can refer to MSDN documentation to get more information about the Runtime Directives Configuration File.

%d bloggers like this: