更新可观察集合时,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;
}
}
我被这个问题困扰已经有一段时间了。这对你们来说可能很简单。
我有一个集合视图,它的项目源显示一个可观察的集合。它在应用程序启动时显示来自用户的消息,然后随着新消息的到来,我想将新消息添加为 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;
}
}