Using ListView with MVVM pattern I get InvalidCastException: Specified cast is not valid

JonAlzaJonAlza ESMember ✭✭

Hello,

I have a problem with ListView and MVVM pattern. This is my environment:

  • Windows 8.1 Pro (x64)
  • Visual Studio Enterprise 2015 Update 3
  • Xamarin 4.2.2.6
  • Xamarin.Forms 2.3.3.180
  • MvvmLight 5.3.0

I started new Blank Xaml App (Xamarin.Forms Portable) and then I uncheck Windows Phone Silverlight 8.1 from portable library targets.

This is my model, RssSchema.cs (nothing special, only some properties):

namespace Rss.Model
{
    public class RssSchema
    {
        public string Id { get; set; }
        public string Title { get; set; }
        public string Summary { get; set; }
        public string Content { get; set; }
        public string ImageUrl { get; set; }
        public string ExtraImageUrl { get; set; }
        public string MediaUrl { get; set; }
        public string FeedUrl { get; set; }
        public string Author { get; set; }
        public DateTime PublishDate { get; set; }
    }
}

My view model, FeedViewModel.cs with FeedTitle and Items properties. To test, in the constructor I fill Items property with 3 RssSchema objects:

namespace Rss.ViewModel
{
    public class FeedViewModel : ViewModelBase
    {
        private ObservableCollection<RssSchema> items = null;
        public ObservableCollection<RssSchema> Items
        {
            get { return this.items; }
            set
            {
                if (this.items == value) { return; }
                this.items = value;
                this.RaisePropertyChanged(nameof(this.Items));
            }
        }

        private string feedTitle = string.Empty;
        public string FeedTitle
        {
            get { return this.feedTitle; }
            set
            {
                if (this.feedTitle == value) { return; }
                this.feedTitle = value;
                this.RaisePropertyChanged(nameof(this.FeedTitle));
            }
        }

        public FeedViewModel()
        {
            List<RssSchema> list = new List<RssSchema>();
            for (int i = 0; i < 3; i++)
            {
                RssSchema item = new RssSchema();
                item.Title = $"Title {i}";
                list.Add(item);
            }
            this.Items = new ObservableCollection<RssSchema>(list);
            this.FeedTitle = "My blog feed";
        }
    }
}

As I'm using MVVM Light I have a ViewModelLocator.cs (nothing special, only Feed property):

namespace Rss.ViewModel
{
    public class ViewModelLocator
    {
        public ViewModelLocator()
        {
            ServiceLocator.SetLocatorProvider(() => SimpleIoc.Default);
            SimpleIoc.Default.Register<FeedViewModel>();
        }

        public FeedViewModel Feed
        {
            get
            {
                return ServiceLocator.Current.GetInstance<FeedViewModel>();
            }
        }

        public static void Cleanup() { }
    }
}

And I create an instace of it in App.xaml:

<?xml version="1.0" encoding="utf-8"?>
<Application xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             x:Class="Rss.App"
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
             d1p1:Ignorable="d"
             xmlns:d1p1="http://schemas.openxmlformats.org/markup-compatibility/2006">
  <Application.Resources>
    <ResourceDictionary>
      <vm:ViewModelLocator x:Key="Locator" d:IsDataSource="True" xmlns:d4p1="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:vm="clr-namespace:Rss.ViewModel" />
    </ResourceDictionary>
  </Application.Resources>
</Application>

Finally, this is my view, FeedPage.xaml with one Label and one ListView:

<?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="Rss.Pages.FeedPage"
             BindingContext="{Binding Source={StaticResource Locator}, Path=Feed}">
  <Grid>
    <Grid.RowDefinitions>
      <RowDefinition Height="Auto"/>
      <RowDefinition Height="*"/>
    </Grid.RowDefinitions>
    <Label Grid.Row="0" Text="{Binding FeedTitle}" HorizontalOptions="Center"/>
    <ScrollView Grid.Row="1" Padding="10">
      <ListView ItemsSource="{Binding Items}" VerticalOptions="Start">
        <!--<ListView.ItemTemplate>
          <DataTemplate>
            <Grid>
              <Label Text="{Binding Title}"/>
            </Grid>
          </DataTemplate>
        </ListView.ItemTemplate>-->
      </ListView>
    </ScrollView>
  </Grid>
</ContentPage>

The Label shows the feed title, so the BindingContext is properly set. As you can see I have the ListView.ItemTemplate in comments. In this way when I run the app I see the 3 items with the default ToString() value (the class complete name):

Rss.Model.RssSchema
Rss.Model.RssSchema
Rss.Model.RssSchema

You can imagine that I don't want to see this content, but if I uncomment the ListView.ItemTemplate part and run the app I get this exception in runtime:

Unhandled Exception:
System.InvalidCastException: Specified cast is not valid.

Do you know what is happening?

Best Answer

Answers

Sign In or Register to comment.