XAM-Consulting / FreshEssentials

FreshEssentials for Xamarin.Forms has ONLY the most common extensions you need for Xamarin.Forms
Apache License 2.0
107 stars 30 forks source link

Invalid Cast Exception with BindablePicker #27

Open ghost opened 7 years ago

ghost commented 7 years ago

I have used FreshEssentials BindablePicker in other projects fine, but am having a very strange problem with a particular Page/PageModel.

I have stripped the Page and PageModel right down to the following: Page:

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:Class="Manager.Pages.Config.RemoteConnectionsPage"
             xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:fe="clr-namespace:FreshEssentials;assembly=FreshEssentials">
    <ContentPage.Content>
        <StackLayout Orientation="Vertical">
            <Label HorizontalOptions="CenterAndExpand" Text="Main Page" />
            <fe:BindablePicker DisplayProperty="Name" ItemsSource="{Binding Environments}" />
        </StackLayout>
    </ContentPage.Content>
</ContentPage>

PageModel:

using System.Collections.Generic;
using FreshMvvm;
using PropertyChanged;

namespace Manager.PageModels.Config
{
    [ImplementPropertyChanged]
    public class RemoteConnectionsPageModel : FreshBasePageModel
    {
        public enum Environment
        {
            Live,
            Test,
            Third
        }

        public class EnvironmentPickerItem
        {
            public string Name {
                get {
                    return Env.ToString ();
                }
            }

            public Environment Env {
                get;
                set;
            }
        }
        public RemoteConnectionsPageModel ()
        {
            List<EnvironmentPickerItem> _Environments;
            _Environments = new List<EnvironmentPickerItem> ();
            _Environments.Add (new EnvironmentPickerItem () { Env = Environment.Live });
            _Environments.Add (new EnvironmentPickerItem () { Env = Environment.Test });
            _Environments.Add (new EnvironmentPickerItem () { Env = Environment.Third });
            this.Environments = _Environments;
        }

        public List<EnvironmentPickerItem> Environments {
            get;
            set;
        }
    }
}

The problem is when I run the application, I get the exception below (full stack trace truncated):

System.InvalidCastException: Specified cast is not valid. at FreshEssentials.Droid.BindablePickerRendererDroid.OnElementChanged (Xamarin.Forms.Platform.Android.ElementChangedEventArgs1[TElement] e) [0x00031] in C:\Users\Michael\Documents\FreshEssentials\src\Droid\Renderers\BindablePickerRendererDroid.cs:46 at Xamarin.Forms.Platform.Android.VisualElementRenderer1[TElement].SetElement (TElement element) [0x000f4] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:190 at Xamarin.Forms.Platform.Android.VisualElementRenderer`1[TElement].Xamarin.Forms.Platform.Android.IVisualElementRenderer.SetElement (Xamarin.Forms.VisualElement element) [0x00027] in C:\BuildAgent3\work\ca3766cfc22354a1\Xamarin.Forms.Platform.Android\VisualElementRenderer.cs:131

Looking at the source for the BindablePickerRendererDroid from the FreshEssentials repository, it appears to be the line:

((ObservableCollection<string>)e.NewElement.Items).CollectionChanged += RowsCollectionChanged;

in this method.

protected override void OnElementChanged(ElementChangedEventArgs<BindablePicker> e)
        {
            if (e.OldElement != null)
                ((ObservableCollection<string>)e.OldElement.Items).CollectionChanged -= RowsCollectionChanged;

            if (e.NewElement != null)
            {
                ((ObservableCollection<string>)e.NewElement.Items).CollectionChanged += RowsCollectionChanged;
                if (Control == null)
                {
                    var button = new AButton(Context) { Focusable = false, Clickable = true, Tag = this, Text = e.NewElement.Title };
                    button.SetOnClickListener(PickerListener.Instance);
                    SetNativeControl(button);
                }
                UpdatePicker();
            }

            base.OnElementChanged(e);
        }

The strange thing is that taking the above exact code into a brand new project works fine. I have checked versions of FreshEssentials and FreshMVVM, and they're identical between the working and non-working projects.

Anyone come across this, and/or any thoughts?

Full Xamarin Studio and other version info below:

=== Xamarin Studio Community ===

Version 6.1.4 (build 1) Installation UUID: 462e6ba8-9cb7-4b87-acc8-9dfb0ab2c6f7 Runtime: Mono 4.6.2 (mono-4.6.0-branch/ac9e222) (64-bit) GTK+ 2.24.23 (Raleigh theme)

Package version: 406020016

=== NuGet ===

Version: 3.4.3.0

=== Xamarin.Profiler ===

Version: 0.33.2 Location: /Applications/Xamarin Profiler.app/Contents/MacOS/Xamarin Profiler

=== Xamarin.Android ===

Version: 7.0.2.42 (Xamarin Studio Community) Android SDK: /Users/jameslavery/Library/Developer/Xamarin/android-sdk-macosx Supported Android versions: 2.3 (API level 10) 4.0.3 (API level 15) 4.1 (API level 16) 4.3 (API level 18) 4.4 (API level 19) 5.0 (API level 21) 5.1 (API level 22) 6.0 (API level 23)

SDK Tools Version: 24.4.1 SDK Platform Tools Version: 23.1 SDK Build Tools Version: 23.0.1

Java SDK: /usr java version "1.7.0_71" Java(TM) SE Runtime Environment (build 1.7.0_71-b14) Java HotSpot(TM) 64-Bit Server VM (build 24.71-b01, mixed mode)

Android Designer EPL code available here: https://github.com/xamarin/AndroidDesigner.EPL

=== Xamarin Android Player ===

Version: 0.6.5 Location: /Applications/Xamarin Android Player.app

=== Apple Developer Tools ===

Xcode 8.0 (11246) Build 8A218a

=== Xamarin.iOS ===

Version: 10.3.1.8 (Xamarin Studio Community) Hash: 7beaef4 Branch: cycle8-xi Build date: 2016-12-20 02:58:14-0500

=== Xamarin.Mac ===

Version: 2.10.0.120 (Xamarin Studio Community)

=== Build Information ===

Release ID: 601040001 Git revision: e606823f2dd01b4552216c013b597a73bec2068f Build date: 2017-01-10 17:28:57-05 Xamarin addins: c92d0626d347aaa02839689eaac2961d24c9f446 Build lane: monodevelop-lion-cycle8

=== Operating System ===

Mac OS X 10.11.6 Darwin Jamess-MacBook-Pro.local 15.6.0 Darwin Kernel Version 15.6.0 Thu Jun 23 18:25:34 PDT 2016 root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64

=== Enabled user installed addins ===

StyleCop Support 1.0.1.9 Gorilla Player 0.9.1.2 XamlStyler 1.0.2

jessejiang0214 commented 7 years ago

I have no idea,

For this line, I copied these code from Xamarin.Forms. ((ObservableCollection)e.NewElement.Items).CollectionChanged += RowsCollectionChanged;

NewElement.Items is Picker.Items. BindablePicker inherit from Picker

Would you please link FreshEssentials source code into your project? So that we can know what's the exception it throw.

ghost commented 7 years ago

Thanks for looking at it. Yes the next step is going to have to be linking the source so we can debug the problem.

rdaniel0 commented 7 years ago

I've pulled the source directly to debug it because I was getting the same InvalidCastException. It's the same line, and it's because e.NewElement.Items is for some reason unable to be cast to ObservableCollection<string>

I have only observed this error on android support verison 25.1.1

I'm going to try and fix it soon (as I need it in my current project asap) and if it works for me, I'll provide a pull request.

veeprox commented 7 years ago

Your binding source MUST be castable to IList or this class will throw an error. My issue is the cast to an IList here on line 99 in BindablePicker.cs;

picker.ItemsSource = (IList) newValue

I have a dictionary of items I wanna show in the picker. I was trying to bind ItemsSource to MyDictionary.Values which is a ValueCollection and isn't castable to IList.

MyDictionary.Values.ToList() fixed my issue.

ManuelArroz commented 7 years ago

View

[https://developer.xamarin.com/guides/xamarin-forms/user-interface/picker/]

This is the recommended technique, which was introduced in Xamarin.Forms 2.3.4.

And [https://developer.xamarin.com/guides/xamarin-forms/user-interface/picker/populating-itemssource/]

acaliaro commented 7 years ago

I have the same problem... before (using Xamarin Studio) no problem with your BindablePicker. Today (uninstalled Xamarin Studio, installe Visual Studio for Mac), the exception.

Changed BindablePicker with XF 2.4.3 Picker, it works

micuentadecasa commented 6 years ago

I had the same problem, changed code to the current code for the BindablePickerRendererDroid.cs and it works now

learsixela commented 6 years ago

Hi, can you help me, I'm trying to run the example on android from VS to Mac and it does not work, do not drop the screen with the "Change source of Picker" button, it throws the same exception, I thank you. (In IOs it works),sorry for my english, it's pretty bad