-
Notifications
You must be signed in to change notification settings - Fork 5
Writing a mapping using a completed action 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 Windows Phone 8 Silverlight that is used to search on contacts (Contacts.SearchAsync https://msdn.microsoft.com/en-US/library/windows/apps/microsoft.phone.userdata.contacts.searchasync(v=vs.105).aspx), requires you to set an event handler for processing de data when it's available.
For example:
Contacts cons = new Contacts();
cons.SearchCompleted += new EventHandler(Contacts_SearchCompleted);
cons.SearchAsync(contactFilterString.Text, contactFilterKind, "Contacts Test #1");
status.Text = "Searching...";The equivalent UWP functionality requires changing the code to something similar to:
Windows.ApplicationModel.Contacts.ContactStore cons = await Windows.ApplicationModel.Contacts.ContactManager.RequestStoreAsync();
(cons.GetContactReader(new Windows.ApplicationModel.Contacts.ContactQueryOptions(contactFilterString.Text, contactFilterKind)).ReadBatchAsync())
.AsTask()
.ContinueWith(Contacts_SearchCompleted,
System.Threading.Tasks.TaskScheduler.FromCurrentSynchronizationContext());
status.Text = "Searching...";Notice that in this particular case we didn't generate 'await'. The reason for this is that, we want to preserve the behavoir of the original application. In this case the code will execute the 'Contacts_SeachCompleted' method when the data is available.
It is common to see that the Contacs search API is used following this pattern:
Contacts contactsInstance = ...; // Instance creation
contactsInstance.SearchCompleted += completedCallback; // Completion event subscription
contactsInstance.SearchAsync(); // Start operationIt turns out that this pattern repeats on other Windows Phone Silverlight API. For example:
| Class | Completition event | Start operation method |
|---|---|---|
| Microsoft.Phone.Tasks.PhotoChooserTask | Completed | Show |
| Microsoft.Phone.UserData.Appointments | SearchCompleted | SearchAsync |
| System.Net.WebClient | DownloadStringCompleted | DownloadStringAsync |
| System.Net.WebClient | OpenReadAsync | OpenReadCompleted |
In this case the UWP conversion tool provides a mechanism for dealing with this situation.
By specifying the COMPLETED_PATTERN_EVENTS and COMPLETED_PATTERN_METHODS metatada elements, the conversion tool will try to identify the pattern described above and perform a conversion that is compatible with the ContinueWith operation described above.
For example for the Contacts/SearchCompleted/SearchAsync operation we can specify the following mapping:
<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.UserData.Contacts">
<map:CodeMapPackage.Maps>
...
<map:CodeMap Kind="Call" MemberName="SearchAsync">
<map:Conditional>
<map:Case>
<map:Case.Condition>
<map:WithMethodCall>
<map:ArgumentCount>3</map:ArgumentCount>
<map:WithArgument Position="0">
<map:AssignName>$queryContents</map:AssignName>
</map:WithArgument>
<map:WithArgument Position="1">
<map:AssignName>$queryKind</map:AssignName>
</map:WithArgument>
<map:WithCalledMemberOwner>
<map:AssignName>$contacts</map:AssignName>
</map:WithCalledMemberOwner>
</map:WithMethodCall>
</map:Case.Condition>
<map:Case.Action>
<map:ReplaceWithTemplate>
<![CDATA[ ($contacts.GetContactReader(new Windows.ApplicationModel.Contacts.ContactQueryOptions($queryContents, $queryKind))
.ReadBatchAsync())
]]>
</map:ReplaceWithTemplate>
</map:Case.Action>
</map:Case>
<map:Default>
<map:Keep/>
</map:Default>
</map:Conditional>
</map:CodeMap>
<map:CodeMap Kind="MemberAccess" MemberName="SearchCompleted">
<map:CodeMap.Action>
<map:CommentOut/>
</map:CodeMap.Action>
</map:CodeMap>
<map:CodeMap Kind="EventDecl" MemberName="SearchCompleted">
<map:ActionSequence>
<map:ReplaceParameterDeclarationType Position="0">
<![CDATA[System.Threading.Tasks.Task<Windows.ApplicationModel.Contacts.ContactBatch>]]>
</map:ReplaceParameterDeclarationType>
<map:ReplaceParameterValue Position="1">
$parameter0Name.Result
</map:ReplaceParameterValue>
<map:RemoveParameter Position="1"/>
</map:ActionSequence>
</map:CodeMap>
</map:CodeMapPackage.Maps>
<map:CodeMapPackage.Metadata>
<map:PackageMetadata Key="COMPLETED_PATTERN_EVENTS" Value="SearchCompleted"/>
<map:PackageMetadata Key="COMPLETED_PATTERN_METHODS" Value="SearchAsync"/>
<map:PackageMetadata Key="ASYNC_MEMBERS" Value="Contacts"/>
</map:CodeMapPackage.Metadata>
</map:CodeMapPackage>
</MapUnit.Elements>
</MapUnit>
See the [Writing a mapping for event handlers](Writing a mapping for event handlers) section for more information on this topic.
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