System.InvalidCastException: Object must implement IConvertible - Xamarin Footer iOS

RaphaelChiorlinRanieriRaphaelChiorlinRanieri ✭✭✭BRMember ✭✭✭

I'm having this exception every time I try to set a footer on ios:

System.InvalidCastException: Object must implement IConvertible.
  at System.Convert.ChangeType (System.Object value, System.Type conversionType, IFormatProvider provider) [0x0005a] in /Users/builder/data/lanes/2377/73229919/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/convert.cs:343
  at Xamarin.Forms.BindingExpression.TryConvert (Xamarin.Forms.BindingExpressionPart part, System.Object& value, System.Type convertTo, Boolean toTarget) [0x00034] in <filename unknown>:0

when I call:

listView.Footer = foot;

Where foot is from type:

public class Model_Footer
    {
        public int pt1 { get; set; }
        public string pt2 { get; set; }
        public double pt3 { get; set; }
        public double pt4 { get; set; }

        public Model_Footer ()
        {
        }
    }

This exception do not crash the app, but the footer do not work as expected.

My footer template is from a type that implements a contentView:

footerTemplate = new DataTemplate (typeof(FooterCell)); 
listView.FooterTemplate = footerTemplate; 

public class FooterCell : ContentView 

if I understand right the footer functionality the listview.Footet should be the binding context for listview.FooterTemplate...
And it works as expected in Android.

Anyone can give a help?

Posts

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri ✭✭✭ BRMember ✭✭✭

    Any one? This seems a bug to me...

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    What do your bindings look like for the footer template? You omitted that part.

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri ✭✭✭ BRMember ✭✭✭

    @adamkemp

    In my footer template I do:

    Model_Footer bindingFooter = new Model_Footer();
    
    protected override void OnBindingContextChanged() {
                if (BindingContext != null) {
                    bindingFooter = (Model_Footer)BindingContext;
                }
                base.OnBindingContextChanged();
            }   
    

    This is what you mean?

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    No, I didn't ask about the binding context. I asked about the bindings themselves. Somewhere you must be calling SetBinding to set up the bindings for the footer view (probably in the constructor for FooterCell). Show me that code.

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri ✭✭✭ BRMember ✭✭✭

    @adamkemp

    By default the binding of FooterTemplate is already the Footer itself.
    This is what I understand from this post

    In my FooterTemplate I I basically override the OnBindingContextChanged as showed and then use the properties as parameters for another function as:

            Model_Footer bindingFooter = new Model_Footer();
    
            protected override void OnBindingContextChanged() {
                        if (BindingContext != null) {
                            bindingFooter = (Model_Footer)BindingContext;
                        }
                        base.OnBindingContextChanged();
                    }  
                   var photo = new Image
                    {
    
                            ...
    
                     };
    
        photo.GestureRecognizers.Add (new TapGestureRecognizer (async sender => {
            doStuff( bindingFooter.pt1 );    //I just use the new properties
        }));
    
  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    I think you're misunderstanding my question. The binding context is not the same thing as the binding. The binding context says where to look for the data that's used for bindings. The bindings themselves set up the link between specific properties in the view and properties in the object set as the binding context. You create the bindings either through XAML using {Binding ...} notation or in C# using the SetBinding method. Setting the binding context has no effect if you don't have any bindings. It's the code that creates the bindings that I want to see.

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri ✭✭✭ BRMember ✭✭✭

    @adamkemp I don't set the binding context, as @CraigDunn said in the topic the listview.Footer obejct will be the binding context of the listview.FooterTemplate by default.

    Here this is my class FooterTemplate:

            public class FooterCell : ContentView
            {
    
                Model_Footer bindingFooter = new Model_Footer();
    
                Image photo;
    
                public FooterCell ()
                {
                    bool clicked = false;
    
                    photo = new Image
                    {
                        Aspect = Aspect.AspectFit,
                        Source = ImageSource.FromFile ("ic_plus.png")
    
                    };
    
                    photo.GestureRecognizers.Add (new TapGestureRecognizer (async sender => {
                        photo.Opacity = 0.6;
                        await photo.FadeTo (1);
    
                        var b = (Image)sender;
    
                        if(!clicked)
                        {
    
                    //ommited the code lot of logic
                        doStuff(bindingFooter.pt1);
    
                            photo.Source = ImageSource.FromFile ("ic_plus_.png");
                            clicked=true;
                        }
    
    
                    }));
    
                    var viewLayout = new StackLayout
                    {
                        Padding = new Thickness(4, 6, 4, 6),
                        Spacing = 1,
                        BackgroundColor = Color.Transparent,
                        VerticalOptions = LayoutOptions.CenterAndExpand,
                        HorizontalOptions = LayoutOptions.CenterAndExpand,
    
                        Orientation = StackOrientation.Horizontal,
                        Children = { photo }
                    };
    
                    this.Content = viewLayout;
                }
    
    
    
                protected override void OnBindingContextChanged() {
                    if (BindingContext != null) {
                        bindingFooter = (Model_Footer)BindingContext;
                    }
                    base.OnBindingContextChanged();
                }
    
            }
    

    All I do in my code is:

            footerTemplate = new DataTemplate (typeof(FooterCell));
            foot.pt1 = 0
            foot.pt2 = "";
            foot.pt3 = 1;
            listView.Footer = foot;
            listView.FooterTemplate = footerTemplate;
    

    Just setting the listview.Footer already trigger the OnBindingContextChanged, because the binding is already setted by default bettewen listview.Footer and listview.FooterTemplate.

    I got the exception in the line I call:

    listView.Footer = foot;
    

    I thought that maybe when I set it, the binding context was changing and trying to do that Cast... but for some reason I get this exception before:

    System.InvalidCastException: Object must implement IConvertible.
      at System.Convert.ChangeType (System.Object value, System.Type conversionType, IFormatProvider provider) [0x0005a] in /Users/builder/data/lanes/2377/73229919/source/maccore/_build/Library/Frameworks/Xamarin.iOS.framework/Versions/git/src/mono/external/referencesource/mscorlib/system/convert.cs:343
      at Xamarin.Forms.BindingExpression.TryConvert (Xamarin.Forms.BindingExpressionPart part, System.Object& value, System.Type convertTo, Boolean toTarget) [0x00034] in <filename unknown>:0
    

    I tried to put a breakpoint on OnBindingContextChanged but it is not hit... just in time I try to change the listview.Footer it already throws an exception.

    My class Model_Footer should implement IConvertible?

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    I don't know how to put this any simpler. The code I'm looking for should have either SetBinding (C#) or {Binding ...} (XAML). I don't care at all how or where you set the binding context. Show me the bindings! If your next post doesn't have the code with one of those words then I can't help you.

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri ✭✭✭ BRMember ✭✭✭

    @adamKemp Thanks for the help.
    I'm sorry but I do not use SetBinding. I did it in a different way.
    As my FooterCell has a button that can only be clickable after the context is set, I do not use SetBindings, what I do is overload the OnBindingContextChange and assign the new object from the bindingContext to a local variable on the FooterCell. This way when the button is clicked the local variable is already with the new bindingContext, because I assign the listview.FooterTemplate after the bindingContext is changed. This way I do not SetBinding.

    But anyway the error is happening before the bindings. I think the bindingContext can't be set because it can not Cast the object in iOS.

    In Android it works just as expected.

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    If you don't use SetBinding or {Binding...} then there is no reason to use BindingContext at all.

    Could you please attach a complete working example project that demonstrates this issue? I don't understand what it is you're doing.

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri ✭✭✭ BRMember ✭✭✭

    Hey @adamkemp sorry for the super delay...
    I did an example...

    The problem do not crash the app, it just is thrown if you set an Exception Catchpoint. You can do this via the Xamarin Studio View -> Debug Windows -> Breakpoints window. In this window, click the "New Exception Catchpoint" button. Then, add System.Exception in the "When an exception is thrown" textbox. For more details go to this link in Custom Breakpoints topic.

    Every Time I set the footer this exception occurs... In Android, the footer works as "expected" even with some complications. But in iOS it don't even shows it. Do not know if the reason is the exception but I couldn't make it work.

    Could you give a help?

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    In this example I think the problem is in this sequence of lines:

            listView.FooterTemplate = new DataTemplate(typeof(HeaderCell));
            listView.Footer = "Waiting...";
            // ...
            listView.Footer = foot;
            listView.FooterTemplate = footerTemplate;
    

    Notice that by the time you get to the listView.Footer = foot line the template is a HeaderCell. A HeaderCell has a binding to ".", expecting a type of string. That makes sense when your Footer is a string, but when you reassign the Footer to be a ModelFooter then it no longer makes sense. That's why it fails to apply the binding properly.

    To make this sequence make sense you should rewrite it like this:

            listView.FooterTemplate = new DataTemplate(typeof(HeaderCell));
            listView.Footer = "Waiting...";
            // ...
    
            listView.Footer = null;
            listView.FooterTemplate = footerTemplate;
            listView.Footer = foot;
    

    Nulling out the footer first ensures that any bound properties will be cleared. Then you set the template, which will initially have no effect because you have no binding context (Footer is null still). Lastly, you assign a real value to Footer, which will cause the new bindings to be updated.

    You could maybe argue that assigning FooterTemplate last should still end up with the right answer, but it's a strange sequence of events that seems to confuse the binding system. I suggest making sure that the bindings are all valid at each step to avoid this kind of issue.

  • RaphaelChiorlinRanieriRaphaelChiorlinRanieri ✭✭✭ BRMember ✭✭✭

    @adamkemp Thanks, you are right this solved the exception issue! :)
    Do you know why in ios... after changing the footerTemplate .. it dont update?
    After I change the template I was hoping it to change from the text to an image but the image do not appear.
    in Android it works as expected.

  • adamkempadamkemp mod USInsider, Developer Group Leader mod

    If you're using the change I suggested and it still doesn't work then report a bug with your example: http://bugzilla.xamarin.com.

Sign In or Register to comment.