question

IvanLabrador-4807 avatar image
0 Votes"
IvanLabrador-4807 asked IvanLabrador-4807 answered

Migrating ListView to CollectionView

I am trying to migrate a ListView to a CollectionView.

In my ListView I use a "DataTemplateSelector" with 2 pages like this:

<?xml version="1.0" encoding="UTF-8" ?>
    <ViewCell
        x:Class="FMPatients.Customs.IncomingViewCell"
        xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms">
        <Grid
    ...
        </Grid>
    </ViewCell>


Since the ViewCell does not exist in the CollectionView, I decided to change the root of the Xaml for a DataTemplate.

<?xml version="1.0" encoding="UTF-8" ?>
    <DataTemplate
        x:Class="FMPatients.Customs.IncomingViewCell"
        xmlns="http://xamarin.com/schemas/2014/forms"
        xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
        xmlns:ffimageloading="clr-namespace:FFImageLoading.Forms;assembly=FFImageLoading.Forms">
        <Grid
    ...
        </Grid>
    </DataTemplate>


My DataTemplateSelector:

class MyDataTemplateSelector : DataTemplateSelector
{
    public MyDataTemplateSelector()
    {
        // Retain instances!
        this.incomingDataTemplate = new DataTemplate(typeof(IncomingViewCell));
        this.outgoingDataTemplate = new DataTemplate(typeof(OutgoingViewCell));
    }

    protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
    {
        try
        {
            return ((ChatMessagesVM)item).IsIncoming ? incomingDataTemplate : outgoingDataTemplate;
        }
        catch (System.Exception ex)
        {
            MicrosoftLogEvent.TrackError(ex);
            return null;
        }

        //var messageVm = item as ChatMessagesVM;
        //if (messageVm == null)
        //    return null;

        //return messageVm.IsIncoming ? incomingDataTemplate : outgoingDataTemplate;
    }

    private readonly DataTemplate incomingDataTemplate;
    private readonly DataTemplate outgoingDataTemplate;
}


I'm not sure if it is correct since I still get the following exception:

 **System.InvalidCastException:** 'Specified cast is not valid.'

Any idea how to do the migration or what may be causing the error.

Thank you.


dotnet-xamarin
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

LeonLu-MSFT avatar image
0 Votes"
LeonLu-MSFT answered

Hello,​

Welcome to our Microsoft Q&A platform!

I add your code, I find you change the ViewCell to the DataTemplate manually, And I use myCollectionView.ItemTemplate = new MyDataTemplateSelector(); to set the ItemTemplate, I get the same error as yours.

Then I follow this article to change your code.

https://docs.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/collectionview/populate-data

Firstly, I change your MyDataTemplateSelector.cs. I change the incomingDataTemplate and outgoingDataTemplate Initialization method, Initialize using injection

public class MyDataTemplateSelector : DataTemplateSelector
    {
        public MyDataTemplateSelector()
        {
            // Retain instances!
           // this.incomingDataTemplate = new DataTemplate(typeof(IncomingViewCell));
          //  this.outgoingDataTemplate = new DataTemplate(typeof(OutgoingViewCell));
        }
        protected override DataTemplate OnSelectTemplate(object item, BindableObject container)
        {
            try
            {
                return ((ChatMessagesVM)item).IsIncoming ? incomingDataTemplate : outgoingDataTemplate;
            }
            catch (System.Exception ex)
            {
                MicrosoftLogEvent.TrackError(ex);
                return null;
            }
            //var messageVm = item as ChatMessagesVM;
            //if (messageVm == null)
            //    return null;
            //return messageVm.IsIncoming ? incomingDataTemplate : outgoingDataTemplate;
        }
        // private readonly DataTemplate incomingDataTemplate;
        // private readonly DataTemplate outgoingDataTemplate;

        public DataTemplate incomingDataTemplate { get; set; }
        public DataTemplate outgoingDataTemplate { get; set; }

    }


Then, change the change the ViewCell to the DataTemplate manually, it is not a correct way to use DataTemplate in the Collectionview, So I move the DataTemplate to the ContentPage.Resources directly, like following xaml.

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" xmlns:local="clr-namespace:CollectionViewDataTemple"
             x:Class="CollectionViewDataTemple.MainPage">
    <ContentPage.Resources>
        <ResourceDictionary>
            <DataTemplate x:Key="IncomingViewCell">
                <Grid>
                    <StackLayout Orientation="Vertical">
                        <Label Text="IncomingViewCell"></Label>
                        <Label Text="{Binding Name}"></Label>
                    </StackLayout>
                </Grid>
            </DataTemplate>

            <DataTemplate x:Key="OutgoingViewCell" >
                <Grid>

                    <StackLayout Orientation="Vertical">
                        <Label Text="OutgoingViewCell"></Label>
                        <Label Text="{Binding Name}"></Label>
                    </StackLayout>
                </Grid>




            </DataTemplate>

            <local:MyDataTemplateSelector x:Key="myDataTemplateSelector"
                           incomingDataTemplate="{StaticResource  IncomingViewCell}"       
                           outgoingDataTemplate="{StaticResource OutgoingViewCell}"
                />
        </ResourceDictionary>
    </ContentPage.Resources>
    <StackLayout>
        <CollectionView x:Name="myCollectionView" Header="Monkeys" ItemsLayout="VerticalGrid,2"
                         ItemTemplate="{StaticResource myDataTemplateSelector}"
                Footer="2019" ItemsSource="{Binding ChatMessagesVMs}">
            
         
        </CollectionView>

    </StackLayout>

</ContentPage>


And here is XAML's background code.

public partial class MainPage : ContentPage
    {
        public  ObservableCollection<ChatMessagesVM> ChatMessagesVMs { get; set; }
        public MainPage()
        {
            InitializeComponent();
            ChatMessagesVMs = new ObservableCollection<ChatMessagesVM>();

            ChatMessagesVMs.Add(new ChatMessagesVM() { IsIncoming=false, Name="test1" });
            ChatMessagesVMs.Add(new ChatMessagesVM() { IsIncoming = true, Name = "test2" });
            ChatMessagesVMs.Add(new ChatMessagesVM() { IsIncoming = false, Name = "test3" });
            ChatMessagesVMs.Add(new ChatMessagesVM() { IsIncoming = true, Name = "test4" });

            BindingContext = this;
        }
    }

   public class ChatMessagesVM
    {
        public string Name { get; set; }
        public bool IsIncoming { get; set; }
    }


Here is running screenshot

105585-image.png

Best Regards,

Leon Lu



If the response is helpful, please click "Accept Answer" and upvote it.

Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.



image.png (14.5 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

IvanLabrador-4807 avatar image
0 Votes"
IvanLabrador-4807 answered

Hello thank you very much for your time, it has worked.

5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.