简体   繁体   中英

Xamarin Forms Collectionview not updating when observable collection is updated

I have been stuck with this issue for quite sometime now. It might be quite simple for you guys.

I have a collection view which has its item source that shows an observable collection. It shows messages from users when the app starts and then as a new message comes, I want to add the new message as the 1st element in the collectionview but it gets distorted and removes the prior items (only from the UI and not the actual observable collection data) and only shows 1 item. And when I navigate to other page and come back it shows correctly. Could someone please help me with this.

Xaml

   <CollectionView Grid.Row="1"  x:Name="myMessagesCV" SelectionMode="Single" SelectionChanged="MyMessagesCV_SelectionChanged" RemainingItemsThresholdReached="MyMessagesCV_RemainingItemsThresholdReached" RemainingItemsThreshold="5">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <StackLayout Padding="8, 8, 8, 0">
                            <Grid Padding="0" ColumnSpacing="0" RowSpacing="0" Margin="2">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition Height="Auto"/>
                                </Grid.RowDefinitions>
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="75"/>
                                    <ColumnDefinition Width="*"/>
                                </Grid.ColumnDefinitions>

                                <ffimageloading:CachedImage x:Name="userImage" Source="{Binding userImage}" Aspect="AspectFill" HeightRequest="75" Grid.Row="0" Grid.Column="0" CacheType="All" DownsampleToViewSize="True">
                                    <ffimageloading:CachedImage.Transformations>
                                        <transformations:CircleTransformation/>
                                    </ffimageloading:CachedImage.Transformations>
                                </ffimageloading:CachedImage>
                                
                                <Grid Grid.Row="0" Grid.Column="1" Padding="5">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="Auto"/>
                                        <RowDefinition Height="Auto"/>
                                    </Grid.RowDefinitions>
                                    <Grid.ColumnDefinitions>
                                        <ColumnDefinition Width="*"/>
                                        <ColumnDefinition Width="Auto"/>
                                    </Grid.ColumnDefinitions>
                                    <Label Padding="10, 0, 0, 5" Text="{Binding userName}" LineBreakMode="TailTruncation" TextColor="Black" FontSize="Medium" Grid.Row="0" Grid.Column="0"/>
                                    <Label Padding="10, 0, 0, 5" Text="{Binding message}" FontAttributes="{Binding newMessage}" FontSize="Small" TextColor="Black"  Grid.Row="1" Grid.Column="0"  HorizontalOptions="StartAndExpand" />
                                    <Image Grid.Row="0" Grid.Column="1" Grid.RowSpan="2" Source="dot.png" Aspect="AspectFill" WidthRequest="10" IsVisible="{Binding IsNewMessage}" HorizontalOptions="Center" VerticalOptions="Center"/>
                                </Grid>

                                <BoxView BackgroundColor="LightGray" HeightRequest="1" Grid.Row="1" Grid.Column="1"/>
                        </Grid>
                    </StackLayout>
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>

Code Behind Page

      public ObservableCollection<Messages> MyMessagesList = new ObservableCollection<Messages>();

      public async void GetMyMessages()
    {
        
            if (IsBusy)
                return;

            IsBusy = true;
            var messages = await FirebaseDataHelper.GetMyMessages(uid);
            var allmyMessages = await Task.WhenAll(FirebaseDataHelper.GetUserMessagesDetail(messages));

            myunreadmsg = 0;
            allmyMessagesCount = messages.Count;
            IsSubscribe = false;
            
            foreach (var message in allmyMessages)
            {
                if (message.Count > 0)
                {
                    for (int i = 0; i < message.Count; i++)
                    {
                        if (message[i].status == "Delivered" && message[i].senderId != uid)
                        {
                            message[i].newMessage = FontAttributes.Bold;
                            message[i].IsNewMessage = true;
                            myunreadmsg++;
                        }

                        if (!MyMessagesList.Any(m => m.otheruserId == message[i].otheruserId) && message[i].message != null)
                            MyMessagesList.Add(message[i]);
                    }
                }
            }

            myMessagesCV.ItemsSource = MyMessagesList;

    }


    public void GetMyNewMessages(Messages messageData)
    {
        IsSubscribe = false;
        myunreadmsg = 0;

        Messages newMessageData = new Messages();
        if (messageData.status == "Delivered" && messageData.senderId != uid)
        {
            newMessageData.newMessage = FontAttributes.Bold;
            newMessageData.IsNewMessage = true;
            newMessageData.otheruserId = messageData.otheruserId;
            newMessageData.senderId = messageData.senderId;
            newMessageData.sellerId = messageData.sellerId;
            myunreadmsg++;
        }
        else
        {
            newMessageData.newMessage = FontAttributes.None;
        }

       
        for (int i = 0; i < MyMessagesList.Count; i++)
        {
            if (MyMessagesList[i].otheruserId == messageData.otheruserId)
            {
                if (i == 0)
                {

                    MyMessagesList[i].message = messageData.message;

                    if (myunreadmsg > 0)
                    {
                        MyMessagesList[i].IsNewMessage = true;
                        MyMessagesList[i].newMessage = FontAttributes.Bold;
                    }
                    break;
                }
                else
                {
                    newMessageData.userName = MyMessagesList[i].userName;
                    newMessageData.userImage = MyMessagesList[i].userImage;
                    newMessageData.message = messageData.message;
                    newMessageData.time = messageData.time;
                    
                    newMessageData.messageId = messageData.messageId;

                    MyMessagesList.Remove(MyMessagesList[i]);
                    MyMessagesList.Insert(0, newMessageData);
                    break;
                }
            }
        }

        myMessagesCV.ItemsSource = MyMessagesList;
    }

Thank you guys. Hope I can solve this.

When your new message arrives, don't set ItemSource again like you do it in your GetMyNewMessages method:

myMessagesCV.ItemsSource = MyMessagesList;

Just insert your new message into MyMessagesList ObservableCollection.

MyMessagesList.Insert(0, newMessageData);

I made a simple project where it is demonstrated.

Here is xaml:

<ContentPage
    x:Class="Search.MainPage"
    xmlns="http://xamarin.com/schemas/2014/forms"
    xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
    BackgroundColor="White">

    <Grid Margin="15">

        <CollectionView
            x:Name="CollectionView"
            HorizontalOptions="FillAndExpand"
            VerticalOptions="FillAndExpand">
            <CollectionView.ItemTemplate>
                <DataTemplate>
                    <Label Text="{Binding}" TextColor="Red" />
                </DataTemplate>
            </CollectionView.ItemTemplate>
        </CollectionView>
    </Grid>

</ContentPage>

And here is code behind of this page:

public partial class MainPage : ContentPage
    {
        public MainPage()
        {
            InitializeComponent();
        }
        public ObservableCollection<int> Data { get; set; } = new ObservableCollection<int>(Enumerable.Range(1, 10));

        protected override void OnAppearing()
        {
            base.OnAppearing();

            Device.StartTimer(TimeSpan.FromSeconds(3), () =>
            {
                Data.Insert(0, new Random().Next(1, 1000));
                return true;
            });

            CollectionView.ItemsSource = Data;
        }
    }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM