Search code examples
c#xamarinxamarin.formscustom-controlsmultitargeting

How to use different base class in custom control depending on platform target?


I have a custom editor that I use for iOS, but for UWP I use another editor called SfRichTextEditor.

Now I wonder how I can create like a shareable class, since they have the same bindableproperties instead of doing what I currently do, which is creating a ContentView on top of them, which is causing:

  1. unnecessary nesting for performance purposes

  2. duplicate code

  3. seems to have trouble with some bindings (not verified, but something strange).

    <ContentView>
        <OnPlatform x:TypeArguments="View">
            <OnPlatform.Platforms>
                <On Platform="iOS">
    
                    <controls:CustomIOSEditor/>
                </On>
                <On Platform="UWP">
                    <controls:CustomUWPEditor/>
                </On>
            </OnPlatform.Platforms>
        </OnPlatform>
    </ContentView>
    

So instead of this approach, I want to have a shareable base class if possible, to reuse the code.

These are the x2 controls that I have today.

My iOS custom control:

public class CustomIOSEditor : Editor // Using regular xamarin editor
{
    public static readonly BindableProperty StringResultCommandProperty =
        BindableProperty.Create(
            nameof(StringResultCommand),
            typeof(ICommand),
            typeof(CustomIOSEditor),
            default(ICommand));

    public object StringResultCommandParameter
    {
        get => GetValue(StringResultCommandParameterProperty);
        set => SetValue(StringResultCommandParameterProperty, value);
    }
}

My UWP custom control:

public class CustomUWPEditor : SfRichTextEditor // Using SfRichTextEditor instead here.
{
    public static readonly BindableProperty StringResultCommandProperty =
        BindableProperty.Create(
            nameof(StringResultCommand),
            typeof(ICommand),
            typeof(CustomUWPEditor),
            default(ICommand));

    public object StringResultCommandParameter
    {
        get => GetValue(StringResultCommandParameterProperty);
        set => SetValue(StringResultCommandParameterProperty, value);
    }
}

Latest clue** enter image description here UPDATE** Shared .csproj: enter image description here

MacOS: enter image description here

Settings: enter image description here

Error: enter image description here


Solution

  • Since all code is common except the inheritance is different, it better to use a compile-time check (no worries of code being messy in this case).

    Xamarin.Forms project does not support Multi-targeting frameworks, at the opposite it next evolution which is called MAUI will.

    Meanwhile you can use MSBuild SDK Extras SDK instead of the default Microsoft.NET.Sdk an (but keep in mind that it is not officially supported), but end result is neat (compile-time check).

    • In YourSharedProject.csproj change <Project Sdk="Microsoft.NET.Sdk"> to <Project Sdk="MSBuild.Sdk.Extras/2.1.2">.
    • Setup the platforms that your projects is targeting and their version:

    Example if you target netstandard2.1 and iOS 10 then change <TargetFramework>netstandard2.1</TargetFramework> to <TargetFrameworks>netstandard2.1;iOS10</TargetFrameworks> by starting with the netstandardxx first.

    • Taget Uwp: <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">$(TargetFrameworks);uap10.0.17763;netcoreapp3.1;net472</TargetFrameworks> (if you have .net framework 4.7.1 installed instead of 4.7.2, replace net472 by net471 (same thing for .net.core and uwp versions).

    At the end, your .csproj file starts will looks like this:

    <Project Sdk="MSBuild.Sdk.Extras/2.1.2">
        <PropertyGroup>
            <TargetFrameworks>netstandard2.1;iOS10</TargetFrameworks>
            <TargetFrameworks Condition=" '$(OS)' == 'Windows_NT' ">
    $(TargetFrameworks);uap10.0.17763;netcoreapp3.1;net472</TargetFrameworks>
    

    All this will enable you to use the symbolic constants in a conditional compile time check:

    public class CustomIOSEditor : 
    #if __iOS__
               Editor     //will inherit from this if we are building against iOS
    #endif
    #if WINDOWS_UWP      //will inherit from this if we are building against uwp
               SfRichTextEditor
    #endif
    {
        public static readonly BindableProperty StringResultCommandProperty =
            BindableProperty.Create(
                nameof(StringResultCommand),
                typeof(ICommand),
                typeof(CustomIOSEditor),
                default(ICommand));
    
        public object StringResultCommandParameter
        {
            get => GetValue(StringResultCommandParameterProperty);
            set => SetValue(StringResultCommandParameterProperty, value);
        }
    }
    

    For targeting other platforms-version:

    • Mac version 20: Xamarin.Mac20
    • Android version 10.0: MonoAndroid10.0
    • tizen version 40: tizen40