Reputation: 101
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.
Upvotes: 2
Views: 4085
Reputation: 11
The other solutions didn't work for me, my workaround is
collectionView.ItemsSource = null;
collectionView.ItemsSource = Data;
everytime I display the CollectionView
Upvotes: 1
Reputation: 11
In my case,I define a name for collectionview:
<CollectionView x:Name="CollectionViewName"
ItemsSource="{Binding MyObservableCollection}" >
</CollectionView>
then in ***.xaml.cs file of view :
public MyViewModel vm;
public MyView()
{
InitializeComponent();
vm = new MyViewModel();
BindingContext = vm;
}
protected override async void OnAppearing()
{
base.OnAppearing();
await vm.LoadData();
CollectionViewName.ItemsSource = null;
CollectionViewName.ItemsSource = vm.MyObservableCollection;
}
in MyViewModel :
[ObservableProperty]
ObservableCollection<myModel> MyObservableCollection=new ObservableCollection<myModel> ();
[RelayCommand]
public async Task LoadData()
{
config = new PartitionSyncConfiguration($"{App.RealmApp.CurrentUser.Id}", App.RealmApp.CurrentUser);
realm = Realm.GetInstance(config);
try
{
var list = realm.All<myModel>().ToList().Where(u=> u.Field== youramount).Reverse<myModel>();
MyObservableCollection= new ObservableCollection<myModel>(list);
}
catch (Exception ex)
{
await Application.Current.MainPage.DisplayPromptAsync("Error", ex.Message);
}
}
Upvotes: 1
Reputation: 2970
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;
}
}
Upvotes: 3