4
votes

In order to be able to create a styling that needs to be done natively in the Xamarin environment, I am using a custom renderer. On the android side, I am receiving an System.InvalidCastException, and I do not know how to fix this issue. I am currently wrapping an Android.Widget.StackView due to this guys suggestion on a previous error I was getting (no default constructor takes 0 arguments error). The error does not seem to happen due to declaration or instantiation, but rather when I add it to the ContentView and happens at the return (found by commenting out the line as shown below).

        MainPage = new ContentPage {
            Content = new StackLayout {
                VerticalOptions = LayoutOptions.Center,
                Children = {
                    item1,
                    item2,
                    item3,
                    item4,
                    item5,
                    item6,
                    //rendererIWantToAdd,//taking out this line make it work. adding it breaks it
                }
            }
        };

Code

RendererView

public class RendererView :  View
{

    public static readonly BindableProperty ImageProperty = BindableProperty.Create(
        propertyName: "Src",
        returnType: typeof(string),
        declaringType: typeof(string),
        defaultValue: ""
    );
    public String Src
    {
        get { return (string)GetValue(ImageProperty); }
        set { SetValue(ImageProperty, value); }
    }

    public static readonly BindableProperty TextProperty = BindableProperty.Create(
        propertyName: "Text",
        returnType: typeof(string),
        declaringType: typeof(string),
        defaultValue: "Hello World"
    );
    public String Text
    {
        get { return (string)GetValue(TextProperty); }
        set { SetValue(TextProperty, value); }
    }

    public static readonly BindableProperty ColorProperty = BindableProperty.Create(
        propertyName: "Color",
        returnType: typeof(string),
        declaringType: typeof(string),
        defaultValue: "#AAAAAA"
    );
    public String Color
    {
        get { return (string) GetValue(ColorProperty); }
        set { SetValue(ColorProperty, value); }
    }
}

RendererViewAndroid

[assembly: ExportRenderer(typeof(Project.RendererView), typeof(stackViewWrapper))]
namespace Project.Droid
{
    public class RendererViewAndroid : ViewRenderer<RendererView, stackViewWrapper>
    {

        Android.Widget.TextView label;
        Android.Widget.ImageView image;

        protected override void OnElementChanged(ElementChangedEventArgs<RendererView> e)
        {
            base.OnElementChanged(e);
            if (Control == null)
            {
                createItem(e);
            }

            if (e.OldElement != null)
            {

                unsubscribe(e);
            }

            if (e.NewElement != null)
            {
                subscribe(e);
            }



        }


        protected void createItem(ElementChangedEventArgs<RendererView> e)
        {


            SetNativeControl(new stackViewWrapper());
            label = new Android.Widget.TextView(Context)
            {
                Text = Element.Text
            };

            image = new Android.Widget.ImageView(Context);
            if (!string.IsNullOrWhiteSpace(Element.Src))
            {
                Context.Resources.GetBitmapAsync(Element.Src).ContinueWith((t) =>
                {
                    var bitmap = t.Result;
                    if (bitmap != null)
                    {
                        image.SetImageBitmap(bitmap);
                        bitmap.Dispose();
                    }
                }, TaskScheduler.FromCurrentSynchronizationContext());

            }
            else {
            //  // clear the image
                image.SetImageBitmap(null);
            }


            Control.AddView(image);
            Control.AddView(label);



        }
        protected void subscribe(ElementChangedEventArgs<RendererView> e)
        {

        }
        protected void unsubscribe(ElementChangedEventArgs<RendererView> e)
        {

        }





        protected override void Dispose(bool disposing)
        {
            base.Dispose(disposing);
        }





    }


    public  class stackViewWrapper : Android.Views.View
    {
        public stackViewWrapper() : base(Android.App.Application.Context)
        {
        }
    }
}

Error Stack Trace

System.InvalidCastException: Specified cast is not valid. at at (wrapper castclass) System.Object:__castclass_with_cache (object,intptr,intptr) at Xamarin.Forms.Registrar1[TRegistrable].GetHandler (System.Type type) [0x0001b] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Core\Registrar.cs:24 at Xamarin.Forms.Registrar1[TRegistrable].GetHandler[TOut] (System.Type type) [0x00000] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Core\Registrar.cs:29 at Xamarin.Forms.Platform.Android.Platform.CreateRenderer (Xamarin.Forms.VisualElement element) [0x00006] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\Platform.cs:281 at Xamarin.Forms.Platform.Android.VisualElementPackager.AddChild (Xamarin.Forms.VisualElement view, IVisualElementRenderer oldRenderer, Xamarin.Forms.Platform.Android.RendererPool pool, Boolean sameChildren) [0x00023] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:72 at Xamarin.Forms.Platform.Android.VisualElementPackager.SetElement (Xamarin.Forms.VisualElement oldElement, Xamarin.Forms.VisualElement newElement) [0x00104] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:204 at Xamarin.Forms.Platform.Android.VisualElementPackager.Load () [0x00000] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:56 at Xamarin.Forms.Platform.Android.VisualElementRenderer1[TElement].SetPackager (Xamarin.Forms.Platform.Android.VisualElementPackager packager) [0x00007] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:327 at Xamarin.Forms.Platform.Android.VisualElementRenderer1[TElement].SetElement (Xamarin.Forms.Platform.Android.TElement element) [0x00111] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:195 at Xamarin.Forms.Platform.Android.VisualElementRenderer1[TElement].Xamarin.Forms.Platform.Android.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00027] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:128 at Xamarin.Forms.Platform.Android.Platform.CreateRenderer (Xamarin.Forms.VisualElement element) [0x0001f] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\Platform.cs:282 at Xamarin.Forms.Platform.Android.VisualElementPackager.AddChild (Xamarin.Forms.VisualElement view, IVisualElementRenderer oldRenderer, Xamarin.Forms.Platform.Android.RendererPool pool, Boolean sameChildren) [0x00023] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:72 at Xamarin.Forms.Platform.Android.VisualElementPackager.SetElement (Xamarin.Forms.VisualElement oldElement, Xamarin.Forms.VisualElement newElement) [0x00104] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:204 at Xamarin.Forms.Platform.Android.VisualElementPackager.Load () [0x00000] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementPackager.cs:56 at Xamarin.Forms.Platform.Android.VisualElementRenderer1[TElement].SetPackager (Xamarin.Forms.Platform.Android.VisualElementPackager packager) [0x00007] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:327 at Xamarin.Forms.Platform.Android.VisualElementRenderer1[TElement].SetElement (Xamarin.Forms.Platform.Android.TElement element) [0x00111] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:195 at Xamarin.Forms.Platform.Android.VisualElementRenderer1[TElement].Xamarin.Forms.Platform.Android.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00027] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:128 at Xamarin.Forms.Platform.Android.Platform.CreateRenderer (Xamarin.Forms.VisualElement element) [0x0001f] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\Platform.cs:282 at Xamarin.Forms.Platform.Android.Platform.AddChild (Xamarin.Forms.VisualElement view, Boolean layout) [0x00015] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\Platform.cs:518 at Xamarin.Forms.Platform.Android.Platform.SetPage (Xamarin.Forms.Page newRoot) [0x00089] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\Platform.cs:406 at Xamarin.Forms.Platform.Android.FormsApplicationActivity.InternalSetPage (Xamarin.Forms.Page page) [0x000b7] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\FormsApplicationActivity.cs:286 at Xamarin.Forms.Platform.Android.FormsApplicationActivity.SetMainPage () [0x00000] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\FormsApplicationActivity.cs:305 at Xamarin.Forms.Platform.Android.FormsApplicationActivity.LoadApplication (Xamarin.Forms.Application application) [0x0002d] in C:\BuildAgent2\work\aad494dc9bc9783\Xamarin.Forms.Platform.Android\FormsApplicationActivity.cs:108 at Project.Droid.MainActivity.OnCreate (Android.OS.Bundle bundle) [0x000ae] in /Users/ryan/project-app-xamarin/Project/Project.Droid/MainActivity.cs:47 at Android.App.Activity.n_OnCreate_Landroid_os_Bundle_ (IntPtr jnienv, IntPtr native__this, IntPtr native_savedInstanceState) [0x00011] in /Users/builder/data/lanes/3340/4e275588/source/monodroid/src/Mono.Android/platforms/android-23/src/generated/Android.App.Activity.cs:2426 at at (wrapper dynamic-method) System.Object:688deba4-7150-4f17-9062-10e53a94164c (intptr,intptr,intptr)

1

1 Answers

1
votes

Not sure if this is actually the root of your issue but it will certainly cause you problems afterwards if it is not.

In your RendererView all of your binding properties should have their declaringType set to the class that they are being declared in, which would be RendererView.

For example your first binding property should look like:

public static readonly BindableProperty ImageProperty = BindableProperty.Create(
    propertyName: "Src",
    returnType: typeof(string),
    declaringType: typeof(RendererView),
    defaultValue: ""
);

Then do the same for all the rest. If that doesn't fix it, definitely let me know.

Edit: According to the OP's comment below, the initial error came from the ExportRenderer line, which needed to declare the RendererView instead of the stackViewWrapper like so:

[assembly: ExportRenderer(typeof(Project.RendererView), typeof(RendererViewAndroid))]