0

I am at a lost.. I haven't been able to figure out why my observable collection isn't updating in real time. I have to close app and reopen it to see the update.. So hopefully someone can point me in the right direction.

Nuget packages - FirebaseDatabase.net MvvmHelpers Xamarin community toolkit Xamarin forms Xamarin essentials

So basically I have a ObservableRangeCollection (from MVVMHelpers) that gets a list of Friends from firebase Realtime database.

Friends class is a pretty simple model class -

public class Friend : ObservableObject
    {
        public Friend()
        {
            DateAdded = DateTime.Today;
        }

        string uid;
        public string UID
        {
            get { return uid; }
            set
            {
                SetProperty(ref uid, value);
            }
        }

        DateTime dateAdded;
        public DateTime DateAdded
        {
            get { return dateAdded; }
            set
            {
                SetProperty(ref dateAdded, value);
            }
        }

        string emailAddress;
        public string EmailAddress
        {
            get { return emailAddress; }
            set
            {
                SetProperty(ref emailAddress, value);
            }
        }

Xaml Page - I have a CollectionView binding to Friends

<CollectionView HorizontalScrollBarVisibility="Default" ItemsSource="{Binding Friends}">
                <CollectionView.ItemsLayout>
                    <LinearItemsLayout ItemSpacing="10" Orientation="Horizontal" />
                </CollectionView.ItemsLayout>
                <CollectionView.ItemTemplate>
                    <DataTemplate>

                        <Frame Margin="0"
                               Padding="0"
                               BackgroundColor="Transparent"
                               BorderColor="Transparent"
                               HasShadow="False">

                            <StackLayout Orientation="Vertical">

                                <Frame Margin="0"
                                       Padding="5"
                                       BorderColor="DarkGray"
                                       CornerRadius="25"
                                       HeightRequest="35"
                                       HorizontalOptions="Center"
                                       WidthRequest="35">
                                    <Image BackgroundColor="Transparent"
                                           HorizontalOptions="Center"
                                           Source="{StaticResource UserIcon}" />
                                </Frame>
                                <Frame Margin="0"
                                       Padding="0"
                                       BackgroundColor="Transparent">
                                    <Label HorizontalTextAlignment="Center"
                                           Style="{Binding TextSmallCaption}"
                                           Text="{Binding EmailAddress}"
                                           TextColor="Black"
                                           VerticalTextAlignment="Center" />
                                </Frame>
                            </StackLayout>
                        </Frame>

                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>

PageViewModel - derives from BaseViewModel - it correctly gets and displays the list of friends

private ObservableRangeCollection<Friend> _friends = new ObservableRangeCollection<Friend>();
        public ObservableRangeCollection<Friend> Friends
        {
            get { return _friends; }
            set
            {
                _friends = value;
                OnPropertyChanged();
            }
        }

public MessagingPageViewModel()
        {
            Title = "Messages";

            services = new DBUserService();
            CameraBtn = new MvvmHelpers.Commands.Command(Camera);
            AddBtn = new MvvmHelpers.Commands.Command(Add);
            AddContactBtn = new MvvmHelpers.Commands.Command(AddContact);

            FriendsList();
        }
public async void FriendsList()
        {
            // Retrieve my UID from preferences
            string myUID = Preferences.Get("UID", string.Empty);

            if (IsBusy)
                return;
            try
            {
                // Retrieve Friends List 
                RetrieveFriendsList(myUID);
            }
            catch (System.Exception ex)
            { 
                await Application.Current.MainPage.DisplayAlert("Error", ex.ToString(), "OK");
            }
            finally
            {
                IsBusy = false;
            }
        }

        private async void RetrieveFriendsList(string myUID)
        {
            var response = await services.RetrieveFriendsList(myUID);
            Friends.ReplaceRange(response);
        }

Modal page - this is where i add a new friend to the list on realtime database Xaml - nothing interesting - just a button to add a new friend. PageViewModel --

private MvvmHelpers.ObservableRangeCollection<Friend> _friends = new MvvmHelpers.ObservableRangeCollection<Friend>();
            public MvvmHelpers.ObservableRangeCollection<Friend> Friends
            {
                get { return _friends; }
                set
                {
                    _friends = value;
                    OnPropertyChanged();
                }
            }
    
    public AddFriendPageViewModel()
            {
                services = new DBUserService();
                AddFriendBtn = new MvvmHelpers.Commands.Command(AddFriend);
    
            }
    
    private void AddFriend(object obj)
            {
                Debug.WriteLine("Selected users to add " + obj);
    
                AddFriendToList(obj.ToString());
            }
    
            private async void AddFriendToList(string uid)
            {
                // Retrieve my UID from preferences
                string myUID = Preferences.Get("UID", string.Empty);
    
                // Retrieve friend INFO
                var dbUserService = new DBUserService();
                var response = await dbUserService.RetrieveUser(uid);
    
                bool result = await dbUserService.RegisterFriendList(myUID, uid, response.EmailAddress);
            }

So once I add a new user to the realtime database I close the page popModalAsync and it doesn't show the updated list. If I close the app and reopen it then it shows the updated list. So I am missing notify property change somewhere.? From what I have learned MVVMHelpers does it all for the most part on its own and CollectionView should trigger property change as soon as the # of members changes. So I am stuck. not sure what I am missing. I kept the unrelevant code out (at least what I though was unrelavant) if you need to see more let me know.. ill update the post. My coding level is not beginner .. its more like medium so if you go all expert on me its going to go over my head :-)

Frank van Puffelen
  • 565,676
  • 79
  • 828
  • 807
ritual69
  • 23
  • 4
  • The setter of Friends you call onpropchange, does that require the property name? – Trevor Feb 25 '21 at 00:10
  • I don't know a lot about Firebase, but I don't see any mechanism that would update `Friends` when the db is updated. Unless it is in `RegisterFriendList`? – Jason Feb 25 '21 at 01:53
  • my understanding is that you need to attach a Listener that will fire an event when the db is updated - are you doing that? – Jason Feb 25 '21 at 02:04

1 Answers1

1

so for anyone having the same issue. i found out by trial an error so not sure which change fixed it but here it goes.

i changed the ObservableRangeCollection back to an ordinary ObservableCollection

private ObservableCollection<Friend> _friends = new ObservableCollection<Friend>();
public ObservableCollection<Friend> Friends
{
    get { return _friends; }
    set
    {
        _friends = value;
        OnPropertyChanged();
    }
}

on the retrieve method I changed it to

private void RetrieveFriendsList(string myUID)
{
    //var response = await services.RetrieveFriendsList(myUID);
    //Friends.ReplaceRange(response);

    Friends = services.RetrieveFriendsList(myUID);
}

on the DBservice i changed the method from task to observablecollection

//public async Task<List<Friend>> RetrieveFriendsList (string myUID)
//{
//    return (await client
//        .Child("Users")
//        .Child(myUID)
//        .Child("FriendList")
//        .OnceAsync<Friend>())
//        .Select(u => new Friend
//        {
//            DateAdded = u.Object.DateAdded,
//            EmailAddress = u.Object.EmailAddress,
//            UID = u.Object.UID
//        }).ToList();
//}

public ObservableCollection<Friend> RetrieveFriendsList(string myUID)
{
    var friendsList = client
        .Child("Users")
        .Child(myUID)
        .Child("FriendList")
        .AsObservable<Friend>()
        .AsObservableCollection();

    return friendsList;
}
ritual69
  • 23
  • 4