Jump to: navigation, search

Difference between revisions of "HowTo:Convert Xamarin XAMLs to Maui"


(Created page with "== Information == === Frame to Border === '''Use Border instead of Frame.''' Frame is deprecated in MAUI. Use Border with `Stroke` instead of `BorderColor`. {| class="wik...")
 
Line 82: Line 82:
 
|}
 
|}
 
== Recommended ==
 
== Recommended ==
 +
=== Extract DataTemplates from UBIKThemes ===
 +
'''Create separate .xamlx files for the following DataTemplates.'''
 +
It's not so easy about the namespaces:
 +
* In our default templates, it's enough to add the following ones to every new separate .xamlx files at the beginning;
 +
    * xmlns:ctrls="clr-namespace:UBIK.MAUI.Controls;assembly=UBIK.MAUI";
 +
    * xmlns:platform="clr-namespace:UBIK.MAUI.Platform.Renderers;assembly=UBIK.MAUI";
 +
    * xmlns:resources="clr-namespace:UBIK.MAUI.Resources;assembly=UBIK.MAUI";
 +
    * xmlns:services="clr-namespace:UBIK.MAUI.Services;assembly=UBIK.MAUI";
 +
    * xmlns:uiservices="clr-namespace:UBIK.UI.Services;assembly=UBIK.UI".
 +
* But we don't know if other namespaces might be used in the custom templates. So it might be necessary to really analyze the namespaces used and find/copy them from the UBIKThemes file.
 +
{| class="wikitable"
 +
!   !! Templates !!  
 +
|-
 +
| UBIKMainItem || UBIKChildItem || UBIKTaskItem
 +
|-
 +
| UBIKTaskProperty || UBIKTaskPropertyString || UBIKTaskPropertyDouble
 +
|-
 +
| UBIKTaskPropertyInt || UBIKTaskPropertyNumeric || UBIKTaskPropertyDateTime
 +
|-
 +
| UBIKTaskPropertyGeoData || UBIKTaskPropertyBool || UBIKTaskPropertyPopup
 +
|-
 +
| UBIKTaskPropertyList || UBIKTaskPropertyGuid || UBIKPropertyItem
 +
|-
 +
| UBIKPropertyTextLengthHint || UBIKPropertyDirectEditButtons || UBIKTaskPropertyEditButtons
 +
|-
 +
| UBIKPropertyDirectItemString || UBIKPropertyDirectItemDouble || UBIKPropertyDirectItemInt
 +
|-
 +
| UBIKPropertyDirectItemMinMax || UBIKPropertyDirectItemNumeric || UBIKPropertyDirectItemDateTime
 +
|-
 +
| UBIKPropertyDirectItemGeoData || UBIKPropertyDirectItemBool || UBIKPropertyDirectItemPopup
 +
|-
 +
| UBIKPropertyDirectItemList || UBIKPropertyDirectItemGuid || UBIKDocumentItem
 +
|-
 +
| UBIKSearchResultItem || UBIKDefaultHotSpot || UBIKAngularLinkHotSpot
 +
|-
 +
| UBIKRoundLinkHotSpot || UBIKInputHotSpot || UBIKSignatureHotSpot
 +
|-
 +
| UBIKObjectHotSpot || UBIKMediaHotSpot ||
 +
|}
 +
=== VideoPlayer Adjustments ===
 +
'''This property is repsonsible for the video player regarding how or if it should get scaled up depending on the value of the
 +
Aspect property'''
 +
{| class="wikitable"
 +
! Xamarin
 +
! MAUI
 +
|-
 +
| <syntaxhighlight lang="xml">VideoPlayer...</syntaxhighlight>
 +
| <syntaxhighlight lang="xml">VideoPlayer Aspect="AspectFit"</syntaxhighlight>
 +
|}
 +
=== VideoPlayer Adjustments ===
 +
'''The UriToVideoSourceConverter is no longer needed because the conversion of the
 +
VideoSource gets done by the MediaElement itself. It is marked as obsolete and should therefore no longer be used.'''
 +
{| class="wikitable"
 +
! Xamarin
 +
! MAUI
 +
|-
 +
| <syntaxhighlight lang="xml"><controls:VideoPlayer... Source="{Binding DocumentViewModel.LocalURI, Converter={StaticResource UriToVideoSource}}"/></syntaxhighlight>
 +
| <syntaxhighlight lang="xml"><controls:VideoPlayer... Source="{Binding DocumentViewModel.LocalURI}"/></syntaxhighlight>
 +
|}
 +
=== VideoPlayer Adjustments ===
 +
'''The StopTimer property is obsolete and no longer needed because the MediaElement behind does the Stop of the VideoPlayer
 +
by itself.'''
 +
{| class="wikitable"
 +
! Xamarin
 +
! MAUI
 +
|-
 +
| <syntaxhighlight lang="xml"><controls:VideoPlayer... StopTimer="{Binding Unloaded}" /></syntaxhighlight>
 +
| <syntaxhighlight lang="xml"><controls:VideoPlayer... /></syntaxhighlight>
 +
|}
 +
=== SearchBar Style Fix on iOS ===
 +
'''On iOS, defining a transparent background for the SearchBar control results in a black text on black background appearance.'''
 +
{| class="wikitable"
 +
! Xamarin
 +
! MAUI
 +
|-
 +
| <syntaxhighlight lang="xml">[issue on iOS only] UBIKThemes: SearchBar style: <Setter Property="BackgroundColor" Value="Transparent" /></syntaxhighlight>
 +
| <syntaxhighlight lang="xml">Delete this setter</syntaxhighlight>
 +
|}
 +
=== Avoid Redundant ControlTemplate in DataTriggers ===
 +
'''This is about finding ControlTemplates that are set in DataTriggers in customized Xamls. When the same template is already set as a ContentView default ControlTemplate, it is recommended to remove the default ControlTemplate on the ContentView. For a detailed description please refer to sheet "Mandatory" in cell 27A-27C.
 +
Behavior that might occur if it remains unchanged: Property editor might not open on Android.'''
 +
{| class="wikitable"
 +
! Xamarin
 +
! MAUI
 +
|-
 +
| <syntaxhighlight lang="xml"><ContentView x:Name="containerName" ControlTemplate="{StaticResource YourTemplate1}">
 +
    <ContentView.Triggers>
 +
        <DataTrigger
 +
            Binding="{Binding Source={x:Reference containerName}, Path=...}"
 +
            TargetType="ContentView"
 +
            Value="true">
 +
            <Setter Property="ControlTemplate"
 +
                    Value="{StaticResource YourTemplate1}" />
 +
        </DataTrigger>
 +
        ...
 +
    </ContentView.Triggers>
 +
</ContentView></syntaxhighlight>
 +
| <syntaxhighlight lang="xml"><ContentView x:Name="containerName">
 +
    <ContentView.Triggers>
 +
        <DataTrigger
 +
            Binding="{Binding Source={x:Reference containerName}, Path=...}"
 +
            TargetType="ContentView"
 +
            Value="true">
 +
            <Setter Property="ControlTemplate"
 +
                    Value="{StaticResource YourTemplate1}" />
 +
        </DataTrigger>
 +
        ...
 +
    </ContentView.Triggers>
 +
</ContentView></syntaxhighlight>
 +
|}
 +
=== Replace TemplateBinding with Binding and Source ===
 +
'''This is about finding SfListViewExt controls in customizings, and if there are TemplateBindings used, it's recommended to replace them with Binding, and the Source reference should be added. For a detailed description please refer to sheet "Mandatory" in cell 26A-26C.
 +
Behavior that might occur if it remains unchanged: Pre-selected item might appear unselected.'''
 +
{| class="wikitable"
 +
! Xamarin
 +
! MAUI
 +
|-
 +
| <syntaxhighlight lang="xml"><ContentView
 +
  ...
 +
  x:Name="YourContentViewName">
 +
 +
  <ContentView.Resources>
 +
      <ResourceDictionary>
 +
        ...
 +
        <ControlTemplate x:Key="YourTemplateKey">
 +
            <ctrls:SfListViewExt
 +
                ItemsSource="{TemplateBinding BindingContext.YourBinding,
 +
                              ...}"
 +
                SelectedItem="{TemplateBinding BindingContext.YourBinding,
 +
                              ...}"
 +
            ... />
 +
        </ControlTemplate>
 +
        ...
 +
      </ResourceDictionary>
 +
  </ContentView.Resources>
 +
 +
  ...
 +
</ContentView></syntaxhighlight>
 +
| <syntaxhighlight lang="xml"><ContentView
 +
  ...
 +
  x:Name="YourContentViewName">
 +
 +
  <ContentView.Resources>
 +
      <ResourceDictionary>
 +
        ...
 +
        <ControlTemplate x:Key="YourTemplateKey">
 +
            <ctrls:SfListViewExt
 +
                ItemsSource="{Binding BindingContext.YourBinding,
 +
                                      Source={x:Reference YourContentViewName},
 +
                                      ...}"
 +
                SelectedItem="{Binding BindingContext.YourBinding,
 +
                                        Source={x:Reference YourContentViewName},
 +
                                        ...}"
 +
            ... />
 +
        </ControlTemplate>
 +
        ...
 +
      </ResourceDictionary>
 +
  </ContentView.Resources>
 +
 +
  ...
 +
</ContentView></syntaxhighlight>
 +
|}
 +
=== Remove TapGestureRecognizer from Main Item ===
 +
'''Swiping on the Main items was broken by Maui (Documented in Information). The workaround is to remove the TapGestureRecognizer from UBIKMainItem, and add ListView-based navigation similar to that found in UBIKChildArea (with an extended binding path for technical reasons).'''
 +
{| class="wikitable"
 +
! Xamarin
 +
! MAUI
 +
|-
 +
| <syntaxhighlight lang="xml">(In UBIKMainItem)
 +
<Grid.GestureRecognizers>
 +
<TapGestureRecognizer Command="{Binding NavigateToChildrenCommand}" />
 +
</Grid.GestureRecognizers></syntaxhighlight>
 +
| <syntaxhighlight lang="xml">[nothing]</syntaxhighlight>
 +
|}
 +
=== Add Navigation Behavior in Child Area ===
 +
{| class="wikitable"
 +
! Xamarin
 +
! MAUI
 +
|-
 +
| <syntaxhighlight lang="xml">(In UBIKChildArea)
 +
[nothing]</syntaxhighlight>
 +
| <syntaxhighlight lang="xml"><controls:SfListViewExt.Behaviors>
 +
<behaviors:EventHandlerBehavior EventName="ItemTapped">
 +
<behaviors:InvokeCommandAction Command="{Binding AppStatus.RootList.Items[0].NavigateToChildrenCommand}" />
 +
</behaviors:EventHandlerBehavior>
 +
</controls:SfListViewExt.Behaviors></syntaxhighlight>
 +
|}
 
== Highly Recommended ==
 
== Highly Recommended ==
 
== Mandatory ==
 
== Mandatory ==
Line 88: Line 275:
  
 
[[Category:How-To|Convert Xamarin XAMLs to Maui]]
 
[[Category:How-To|Convert Xamarin XAMLs to Maui]]
[[Category:XAML|Convert Xamarin XAMLs to Maui]]
 
 
[[Category:MAUI|Convert Xamarin XAMLs to Maui]]
 
[[Category:MAUI|Convert Xamarin XAMLs to Maui]]
 +
[[Category:XAML|Convert Xamarin XAMLs to Maui]]

Revision as of 15:15, 24 July 2025

Information

Frame to Border

Use Border instead of Frame. Frame is deprecated in MAUI. Use Border with `Stroke` instead of `BorderColor`.

Xamarin MAUI
<Frame ... /> <Border ... />

LayoutOptions with "...AndExpand"

Replace "...AndExpand" with Grid layout. Horizontal/VerticalOptions ending in "...AndExpand" are deprecated. Use Grid with `ColumnDefinition Width="*"` for expansion.

GlyphLabel and Styles

Use Label with new styles. Custom controls like `GlyphLabel` are no longer needed. Use `Label` with styles like `UBIKSymbolText`.

Xamarin MAUI
controls:GlyphLabel Label with UBIKSymbolText style

SfTabView Virtualization

Enable virtualization. Add `EnableVirtualization="True"` to all SfTabView instances or styles.

Swipe Menu Icons on Android

Refactor swipe templates and label styles. Icons in swipe menus were truncated on Android. Fixed via refactoring.

Color Style Changes

Dark theme adjustments. Changes to color styles may affect appearance. Review usage of `UBIKDarkThemeColor`, `UBIKDarkTextColor`, etc.

Strikethrough Converter

Use `TextDecorations="Strikethrough"` instead of converter.

Xamarin MAUI
Text="{Binding ..., Converter={StaticResource StrikethroughConverter}}" Text="{Binding ...}" TextDecorations="Strikethrough"

Button Disabled Trigger

Add trigger for disabled buttons. Maui buttons don’t visually change when disabled. Add trigger to style.

TapGestureRecognizer Replacement

Use TappedBehavior instead. TapGestureRecognizer now intercepts taps. Use `TappedBehavior` to avoid conflicts.

Xamarin MAUI
<... .GestureRecognizers><TapGestureRecognizer Command="{Binding ...}" /></... .GestureRecognizers> <... .Behaviors><behaviors:TappedBehavior><behaviors:InvokeCommandAction Command="{Binding ...}" /></behaviors:TappedBehavior></... .Behaviors>

TapGestureRecognizer and Swipe Conflict

Remove TapGestureRecognizer from root Grid. TapGestureRecognizer blocks swipe behavior. Remove it and adapt parent list to trigger navigation.

Navigation in UBIKChildItem

Use EventHandlerBehavior for navigation.

Xamarin MAUI
[none] <controls:SfListViewExt.Behaviors><behaviors:EventHandlerBehavior EventName="ItemTapped"><behaviors:InvokeCommandAction Command="{Binding AppStatus.RootList.Items[0].NavigateToChildrenCommand}" /></behaviors:EventHandlerBehavior></controls:SfListViewExt.Behaviors>

Recommended

Extract DataTemplates from UBIKThemes

Create separate .xamlx files for the following DataTemplates. It's not so easy about the namespaces:

  • In our default templates, it's enough to add the following ones to every new separate .xamlx files at the beginning;
   * xmlns:ctrls="clr-namespace:UBIK.MAUI.Controls;assembly=UBIK.MAUI";
   * xmlns:platform="clr-namespace:UBIK.MAUI.Platform.Renderers;assembly=UBIK.MAUI";
   * xmlns:resources="clr-namespace:UBIK.MAUI.Resources;assembly=UBIK.MAUI";
   * xmlns:services="clr-namespace:UBIK.MAUI.Services;assembly=UBIK.MAUI";
   * xmlns:uiservices="clr-namespace:UBIK.UI.Services;assembly=UBIK.UI".
  • But we don't know if other namespaces might be used in the custom templates. So it might be necessary to really analyze the namespaces used and find/copy them from the UBIKThemes file.
  Templates  
UBIKMainItem UBIKChildItem UBIKTaskItem
UBIKTaskProperty UBIKTaskPropertyString UBIKTaskPropertyDouble
UBIKTaskPropertyInt UBIKTaskPropertyNumeric UBIKTaskPropertyDateTime
UBIKTaskPropertyGeoData UBIKTaskPropertyBool UBIKTaskPropertyPopup
UBIKTaskPropertyList UBIKTaskPropertyGuid UBIKPropertyItem
UBIKPropertyTextLengthHint UBIKPropertyDirectEditButtons UBIKTaskPropertyEditButtons
UBIKPropertyDirectItemString UBIKPropertyDirectItemDouble UBIKPropertyDirectItemInt
UBIKPropertyDirectItemMinMax UBIKPropertyDirectItemNumeric UBIKPropertyDirectItemDateTime
UBIKPropertyDirectItemGeoData UBIKPropertyDirectItemBool UBIKPropertyDirectItemPopup
UBIKPropertyDirectItemList UBIKPropertyDirectItemGuid UBIKDocumentItem
UBIKSearchResultItem UBIKDefaultHotSpot UBIKAngularLinkHotSpot
UBIKRoundLinkHotSpot UBIKInputHotSpot UBIKSignatureHotSpot
UBIKObjectHotSpot UBIKMediaHotSpot

VideoPlayer Adjustments

This property is repsonsible for the video player regarding how or if it should get scaled up depending on the value of the Aspect property

Xamarin MAUI
VideoPlayer...
VideoPlayer Aspect="AspectFit"

VideoPlayer Adjustments

The UriToVideoSourceConverter is no longer needed because the conversion of the VideoSource gets done by the MediaElement itself. It is marked as obsolete and should therefore no longer be used.

Xamarin MAUI
<controls:VideoPlayer... Source="{Binding DocumentViewModel.LocalURI, Converter={StaticResource UriToVideoSource}}"/>
<controls:VideoPlayer... Source="{Binding DocumentViewModel.LocalURI}"/>

VideoPlayer Adjustments

The StopTimer property is obsolete and no longer needed because the MediaElement behind does the Stop of the VideoPlayer by itself.

Xamarin MAUI
<controls:VideoPlayer... StopTimer="{Binding Unloaded}" />
<controls:VideoPlayer... />

SearchBar Style Fix on iOS

On iOS, defining a transparent background for the SearchBar control results in a black text on black background appearance.

Xamarin MAUI
[issue on iOS only] UBIKThemes: SearchBar style: <Setter Property="BackgroundColor" Value="Transparent" />
Delete this setter

Avoid Redundant ControlTemplate in DataTriggers

This is about finding ControlTemplates that are set in DataTriggers in customized Xamls. When the same template is already set as a ContentView default ControlTemplate, it is recommended to remove the default ControlTemplate on the ContentView. For a detailed description please refer to sheet "Mandatory" in cell 27A-27C. Behavior that might occur if it remains unchanged: Property editor might not open on Android.

Xamarin MAUI
<ContentView x:Name="containerName" ControlTemplate="{StaticResource YourTemplate1}">
    <ContentView.Triggers>
        <DataTrigger
           Binding="{Binding Source={x:Reference containerName}, Path=...}"
           TargetType="ContentView"
           Value="true">
            <Setter Property="ControlTemplate"
                   Value="{StaticResource YourTemplate1}" />
        </DataTrigger>
        ...
    </ContentView.Triggers>
</ContentView>
<ContentView x:Name="containerName">
    <ContentView.Triggers>
        <DataTrigger
           Binding="{Binding Source={x:Reference containerName}, Path=...}"
           TargetType="ContentView"
           Value="true">
            <Setter Property="ControlTemplate"
                   Value="{StaticResource YourTemplate1}" />
        </DataTrigger>
        ...
    </ContentView.Triggers>
</ContentView>

Replace TemplateBinding with Binding and Source

This is about finding SfListViewExt controls in customizings, and if there are TemplateBindings used, it's recommended to replace them with Binding, and the Source reference should be added. For a detailed description please refer to sheet "Mandatory" in cell 26A-26C. Behavior that might occur if it remains unchanged: Pre-selected item might appear unselected.

Xamarin MAUI
<ContentView
  ...
  x:Name="YourContentViewName">

   <ContentView.Resources>
      <ResourceDictionary>
         ...
         <ControlTemplate x:Key="YourTemplateKey">
             <ctrls:SfListViewExt
                ItemsSource="{TemplateBinding BindingContext.YourBinding,
                             ...}"

                SelectedItem="{TemplateBinding BindingContext.YourBinding,
                             ...}"

            ... />
         </ControlTemplate>
         ...
      </ResourceDictionary>
   </ContentView.Resources>

   ...
</ContentView>
<ContentView
  ...
  x:Name="YourContentViewName">

   <ContentView.Resources>
      <ResourceDictionary>
         ...
         <ControlTemplate x:Key="YourTemplateKey">
             <ctrls:SfListViewExt
                ItemsSource="{Binding BindingContext.YourBinding,
                                      Source={x:Reference YourContentViewName},
                                      ...}"

                SelectedItem="{Binding BindingContext.YourBinding,
                                       Source={x:Reference YourContentViewName},
                                       ...}"

            ... />
         </ControlTemplate>
         ...
      </ResourceDictionary>
   </ContentView.Resources>

   ...
</ContentView>

Remove TapGestureRecognizer from Main Item

Swiping on the Main items was broken by Maui (Documented in Information). The workaround is to remove the TapGestureRecognizer from UBIKMainItem, and add ListView-based navigation similar to that found in UBIKChildArea (with an extended binding path for technical reasons).

Xamarin MAUI
(In UBIKMainItem)
<Grid.GestureRecognizers>
        <TapGestureRecognizer Command="{Binding NavigateToChildrenCommand}" />
</Grid.GestureRecognizers>
[nothing]

Add Navigation Behavior in Child Area

Xamarin MAUI
(In UBIKChildArea)
[nothing]
<controls:SfListViewExt.Behaviors>
        <behaviors:EventHandlerBehavior EventName="ItemTapped">
                <behaviors:InvokeCommandAction Command="{Binding AppStatus.RootList.Items[0].NavigateToChildrenCommand}" />
        </behaviors:EventHandlerBehavior>
</controls:SfListViewExt.Behaviors>

Highly Recommended

Mandatory

SfTabView

OnPlatform + OnIdiom backup