2
votes

I'm trying to create a custom ButtonRenderer for Xamarin.Forms. Here is a simple test I've been trying to put up together following some tutorials, but I can's seem to make it work.

Here is my .xaml page:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="TestProject.MainPage">
    <ContentPage.Content>
        <Button VerticalOptions="Center" HorizontalOptions="Center"></Button>
    </ContentPage.Content>
</ContentPage>

And here is my custom rendered: (it is placed in the Android project)

[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(CustomButtonRenderer))]
namespace TestProject.Droid.CustomRenderers
{
    public class CustomButtonRenderer: ButtonRenderer
    {
        public CustomButtonRenderer(Context context) : base(context)
        {
        }

        protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
        {
            base.OnElementChanged(e);
            Control.SetBackgroundColor(Android.Graphics.Color.Red);
        }
    }
}

But it never gets called and my app crashes. My logcat shows:

System.Reflection.TargetInvocationException: Exception has been thrown by the target of an invocation. ---> Java.Lang.ClassNotFoundException: Didn't find class "md5dba8ede99752acada1f5ba384c7cf839.CustomButtonRenderer" on path: DexPathList[[zip file "/data/app/com.companyname.TestProject-1/base.apk"],nativeLibraryDirectories=[/data/app/com.companyname.GN.Mobile.TestProject-1/lib/arm, /data/app/com.companyname.GN.Mobile.TestProject-1/base.apk!/lib/armeabi-v7a, /vendor/lib, /system/lib]]

Am I missing something here?

2
It looks pretty right. Have you tried the classic 'clean', delete obj and bin files, 'rebuild' and retry? - Diego Rafael Souza
@DiegoRafaelSouza - Yes, I have cleaned, deleted caches, etc... I have started a new clean project and tried to create just these classes... and nothing! :( - LcSalazar
What's your XF version? I'm using Xamarin 4.7.10.33, Xamarin.Android 8.0.2.1 and Xamarin.Forms 2.3.4.247... the ButtonRenderer constructor is parameterless - Diego Rafael Souza
Try to create new class wich inherits from button... es: MyButton : Button.... and in custom render place MyButton instead of button.. - purplesoft
Have you set up a breakpoint in the element changed method and checked if the method throws an exception? You should not just call something on the control without an antecedent null check. Watch this presentation of jason smiths about custom renderers. at 17:12 he starts showing the pattern. - Csharpest

2 Answers

2
votes

I'm still investigating on this. Your class gets shrunk because it's not statically linked in your PCL. You avoid that by giving a name to your classes like this:

[Activity(Name = "somepackage.custombuttonrenderer")]
public class CustomButtonRenderer: ButtonRenderer
{ }

If you're able to target the minimum Android version to Android 5.0 (Api 21) this problem should disappear as another version of the Dex file is used.

-1
votes

replace CustomButtonRenderer code to below code.

[assembly: ExportRenderer(typeof(Xamarin.Forms.Button), typeof(CustomButtonRenderer))]
namespace TestProject.Droid.CustomRenderers
{
public class CustomButtonRenderer: ButtonRenderer
{
    public CustomButtonRenderer(Context context) : base(context)
    {
    }

    protected override void OnElementChanged(ElementChangedEventArgs<Xamarin.Forms.Button> e)
    {
        base.OnElementChanged(e);
        if (e.OldElement != null)
        {
            return;
        }
        var nativeButton = (Android.Widget.Button)this.Control;
        nativeButton.SetBackgroundColor(Android.Graphics.Color.Gray);

    }
}
}