更新可观察集合时,Xamarin Forms Collectionview 不更新

Xamarin Forms Collectionview not updating when observable collection is updated

我被这个问题困扰已经有一段时间了。这对你们来说可能很简单。

我有一个集合视图,它的项目源显示一个可观察的集合。它在应用程序启动时显示来自用户的消息,然后随着新消息的到来,我想将新消息添加为 collectionview 中的第一个元素,但它会变形并删除先前的项目(仅来自 UI 和不是实际可观察​​的收集数据)并且只显示 1 个项目。当我导航到其他页面并返回时,它会正确显示。有人可以帮我解决这个问题吗?

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>

页面隐藏代码

      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;
    }

谢谢你们。希望我能解决这个问题。

当您的新消息到达时,不要像在 GetMyNewMessages 方法中那样再次设置 ItemSource:

myMessagesCV.ItemsSource = MyMessagesList;

只需将您的新消息插入 MyMessagesList ObservableCollection。

MyMessagesList.Insert(0, newMessageData);

我做了一个简单的项目来演示它。

这里是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>

这是此页面的隐藏代码:

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;
        }
    }