-
Notifications
You must be signed in to change notification settings - Fork 5
Writing a mapping for using an initialization pattern
The mappings mechanism works by processing individual API usages. For example you can write a code mapping for a specific method call such as System.Windows.MessageBox.Show. However there are scenarios where several elements could be converted to one element. For example the PhoneCallTask class https://msdn.microsoft.com/library/windows/apps/microsoft.phone.tasks.phonecalltask(v=vs.105).aspx (and several other task classes) work by following a pattern like this:
PhoneCallTask phoneCallTask = new PhoneCallTask();
phoneCallTask.PhoneNumber = model.PhoneNumber;
phoneCallTask.DisplayName = model.FullName;
phoneCallTask.Show();The equivalent UWP code for this group of instructions is the following:
Windows.ApplicationModel.Calls.PhoneCallManager.ShowPhoneCallUI(model.PhoneNumber, model.FullName);The conversion tool provides a way to deal with these kind of scenarios where it's common to find a group of initialization statements and a call to an action method.
<MapUnit xmlns="clr-namespace:Mobilize.Mappers.Extensibility.Core;assembly=Mobilize.ExtensibleMappers"
xmlns:map="clr-namespace:Mobilize.Mappers.Extensibility.Code;assembly=Mobilize.ExtensibleMappers">
<MapUnit.Elements>
<map:CodeMapPackage Type="Microsoft.Phone.Tasks.PhoneCallTask">
<map:CodeMapPackage.Maps>
...
</map:CodeMapPackage.Maps>
<map:CodeMapPackage.Metadata>
<map:PackageMetadata Key="GROUP_INIT_STATEMENTS" Value="true"/>
</map:CodeMapPackage.Metadata>
</map:CodeMapPackage>
</MapUnit.Elements>
</MapUnit>With this metadata element we instruct the migration tool to search for this initialization pattern and group statements in a way it is easier to manipulate using common mapping elements.
ere's an example of how this directive operates:

Having this grouping we can write a mapping as follows:
<MapUnit xmlns="clr-namespace:Mobilize.Mappers.Extensibility.Core;assembly=Mobilize.ExtensibleMappers"
xmlns:map="clr-namespace:Mobilize.Mappers.Extensibility.Code;assembly=Mobilize.ExtensibleMappers">
<MapUnit.Elements>
<map:CodeMapPackage Type="Microsoft.Phone.Tasks.PhoneCallTask">
<map:CodeMapPackage.Maps>
<map:CodeMap Kind="Call" MemberName="Show">
<map:Conditional>
<map:Case>
<map:Case.Condition>
<map:WithCalledMemberOwner>
<map:WithConstructorCall>
<map:WithMemberInitValue MemberName="PhoneNumber">
<map:AssignName>$phoneNumber</map:AssignName>
</map:WithMemberInitValue>
<map:WithMemberInitValue MemberName="DisplayName">
<map:AssignName>$displayName</map:AssignName>
</map:WithMemberInitValue>
</map:WithConstructorCall>
</map:WithCalledMemberOwner>
</map:Case.Condition>
<map:Case.Action>
<map:ReplaceWithTemplate>
Windows.ApplicationModel.Calls.PhoneCallManager.ShowPhoneCallUI($phoneNumber, $displayName)
</map:ReplaceWithTemplate>
</map:Case.Action>
</map:Case>
<map:Default>
<map:Keep/>
</map:Default>
</map:Conditional>
</map:CodeMap>
</map:CodeMapPackage.Maps>
<map:CodeMapPackage.Metadata>
<map:PackageMetadata Key="GROUP_INIT_STATEMENTS" Value="true"/>
</map:CodeMapPackage.Metadata>
</map:CodeMapPackage>
</MapUnit.Elements>
</MapUnit>As shown above, when the MapPackage of a class specifies GROUP_INIT_STATEMENTS metadata element, the conversion tool will try to group the initalization statements before applying mapping. Once the mappings are groupped we can apply a complex mapping such as:

There maybe scenarios where we can't group initialization statements as shown above. For example:
PhoneCallTask phoneCallTask;
void MyMethod()
{
phoneCallTask = CreatePhoneCallTask();
SetPhoneEntryNumber(model, phoneCallTask);
if (model.FullName == "Some special name")
{
SetSpecialName(model, phoneCallTask);
}
DoSomeTask(phoneCallTask);
}
private static void DoSomeTask(PhoneCallTask phoneCallTask)
{
phoneCallTask.Show();
}
private static void SetSpecialName(MyPhoneEntryModel model, PhoneCallTask phoneCallTask)
{
phoneCallTask.DisplayName = model.FullName;
}
private static void SetPhoneEntryNumber(MyPhoneEntryModel model, PhoneCallTask phoneCallTask)
{
phoneCallTask.PhoneNumber = model.PhoneNumber;
}
private static PhoneCallTask CreatePhoneCallTask()
{
PhoneCallTask phoneCallTask = new PhoneCallTask();
return phoneCallTask;
}For these scenarios it is better to use a helper class which provides the equivalent functionality on UWP. See the [Adding helper classes](Adding helper classes) for more information. The helper class we will use for this example looks like this:
using Windows.ApplicationModel.Calls;
namespace UpgradeHelpers {
class PhoneTaskHelper
{
public string DisplayName { get; internal set; }
public string PhoneNumber { get; internal set; }
internal PhoneTaskHelper()
{
DisplayName = "";
}
internal void Show()
{
PhoneCallManager.ShowPhoneCallUI(PhoneNumber, DisplayName);
}
}
}Having this helper class we can include it using the following mapping:
<map:CodeMap Kind="Type">
<map:Conditional>
<map:Case>
<map:Case.Condition>
<map:DoesNotContainAnnotation>GROUP_INIT_STATEMENTS</map:DoesNotContainAnnotation>
</map:Case.Condition>
<map:Case.Action>
<map:ActionSequence>
<map:AddHelper Path="..\Helpers\PhoneTaskHelper.cs" />
<map:ReplaceClassUsage NewNamespace="UpgradeHelpers" NewClassName="PhoneTaskHelper" />
</map:ActionSequence>
</map:Case.Action>
</map:Case>
<map:Default><map:Keep/></map:Default>
</map:Conditional>
</map:CodeMap>The DoesNotContainAnnotation condition verifies that the current type is not part of an identified GROUP_INIT_STATEMENTS pattern . The converted code for the previous example is the following:
UpgradeHelpers.PhoneTaskHelper phoneCallTask;
void MyMethod()
{
phoneCallTask = CreatePhoneCallTask();
SetPhoneEntryNumber(model, phoneCallTask);
if ( model.FullName == "Some special name" )
{
SetSpecialName(model, phoneCallTask);
}
DoSomeTask(phoneCallTask);
}
private static void DoSomeTask(UpgradeHelpers.PhoneTaskHelper phoneCallTask)
{
phoneCallTask.Show();
}
private static void SetSpecialName(MyPhoneEntryModel model, UpgradeHelpers.PhoneTaskHelper phoneCallTask)
{
phoneCallTask.DisplayName = model.FullName;
}
private static void SetPhoneEntryNumber(MyPhoneEntryModel model, UpgradeHelpers.PhoneTaskHelper phoneCallTask)
{
phoneCallTask.PhoneNumber = model.PhoneNumber;
}
private static UpgradeHelpers.PhoneTaskHelper CreatePhoneCallTask()
{
UpgradeHelpers.PhoneTaskHelper phoneCallTask = new UpgradeHelpers.PhoneTaskHelper();
return phoneCallTask;
}Contact us for more information
Overview
Writing mappings
Code Mapping Actions
- ActionSequence
- AddHelper
- AddNamespaceImport
- AddPreStatementFromTemplate
- CommentOut
- Conditional
- Keep Code Mapping Action
- MarkAsNotMapped
- RedirectCall
- RedirectCallToInnerMember
- RedirectIndexer
- RedirectProperty
- RemoveCurrentStatement
- RemoveParameter
- ReplaceClassUsage
- ReplaceMethodBodyWithTemplate
- ReplaceParameterDeclarationType
- ReplaceParameterMember
- ReplaceParameterValue
- ReplaceWithMethodCall
- ReplaceWithProperty
- ReplaceWithTemplate
Code Mapping Conditions
- AllConditionsApply
- ArgumentCount
- AssignName
- AssignNameToArgumentRange
- IsExpressionOfType
- IsStringLiteralMatchingRegex
- WithArgument
- WithAssignment
- WithAssignmentLeftSide
- WithAssignmentRightSide
- WithCalledMemberOwner
- WithCalledMethodExpression
- WithConstructorCall
- WithLambdaExpressionBody
- WithLambdaExpressionParameter
- WithLeftSideOfDottedAccess
- WithMemberInitValue
- WithMethodCall
XAML mapping actions
- ActionSequence
- AddStatementToConstructorFromTemplate
- BindPropertyValueElement Xaml mapping action
- ChangeEventHandlerEventArgsType
- CommentOutElement
- CommentOutProperty
- MarkAsNotMapped
- MoveValueToContentProperty
- RemoveNamespaceDeclaration
- RenameElement
- RenameProperty
- ReplaceAttributeValue
- ReplaceEventHandlerBodyWithTemplate
- ReplaceEventHandlerParameterMember
- ReplaceNamespaceDeclaration
- ReplacePropertyValueWithParentResource
- ReplaceStaticResourceWithThemeResource
- SetPropertyValueToComplexElement
- SetPropertyValueToSimpleValue
- WrapContent
XAML mapping conditions
Misc