2

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

DiddanDo
  • 401
  • 1
  • 5
  • 15

2 Answers2

1

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
Cfun
  • 8,442
  • 4
  • 30
  • 62
  • Oh wow thats very nice indeed. I will give it a go now to see if it works. Any idea if there are any known bugs (since it is not officially supported yet)? – DiddanDo Jan 10 '21 at 06:27
  • Do you know what to type when it comes to macOS for instance? v2.0 Xamarin.Mac this is the targetversion i find when digging into its .csproj – DiddanDo Jan 10 '21 at 06:47
  • 1
    Indeed `Xamarin.Mac` + version appended without any space. I have updated my answer. For bugs you can always take a the repo I have linked and see /issues. – Cfun Jan 10 '21 at 10:03
  • Hmm having issues. It takes the compiler like 20 sec to calculate that it is missing a Type, for the custom class. Not sure if its because xamarin mac is not 2.1. supported? I am not sure how i can make it 2.1 compatibable. – DiddanDo Jan 10 '21 at 10:56
  • i test both - netstandard2.1;Xamarin.Mac20 and also netstandard2.0;Xamarin.Mac20 – DiddanDo Jan 10 '21 at 11:03
  • Hm i presume i also have it on the latest version ? Where could i check this? I am very new on developing for Xamarin.Mac – DiddanDo Jan 10 '21 at 11:07
  • Could you share the error, maybe the issue is in your project? (to be honest I don't have any experience on Mac develpment..) – Cfun Jan 10 '21 at 11:08
  • Check updated post to see the screenshots of issue + setup. And to explain error, i can press play, it builds for 20 sec, then it gives me the "Type expected (CS1031)" where the inherited class goes (not showing red though as u would expect the IDE to do) – DiddanDo Jan 10 '21 at 11:18
0

What you are looking for is SetNativeControl().

Check this example for instance,

https://learn.microsoft.com/en-us/xamarin/xamarin-forms/app-fundamentals/custom-renderer/view#creating-the-custom-renderer-on-uwp

Pasting same sample from above link here

NOTE - CameraPreview in below sample is Xamarin.Form element and CaptureElement is a UWP control

[assembly: ExportRenderer(typeof(CameraPreview), typeof(CameraPreviewRenderer))]
namespace CustomRenderer.UWP
{
    public class CameraPreviewRenderer : ViewRenderer<CameraPreview, Windows.UI.Xaml.Controls.CaptureElement>
    {
        ...
        CaptureElement _captureElement;
        bool _isPreviewing;

        protected override void OnElementChanged(ElementChangedEventArgs<CameraPreview> e)
        {
            base.OnElementChanged(e);

            if (e.OldElement != null)
            {
                // Unsubscribe
                Tapped -= OnCameraPreviewTapped;
                ...
            }
            if (e.NewElement != null)
            {
                if (Control == null)
                {
                  ...
                  _captureElement = new CaptureElement();
                  SetupCamera();
                  SetNativeControl(_captureElement);
                }
            }
        }

        ...
    }
}
Yogesh
  • 1,565
  • 1
  • 19
  • 46
  • isn't an overkill to use a custom renderer in this case ? I don't see how this will remedy to "duplicate code"? – Cfun Jan 09 '21 at 17:43
  • Yeah, then i would have to write platform specific code for the platforms, i think there should be better ways to solve it. – DiddanDo Jan 10 '21 at 06:47