Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
93 views
in Technique[技术] by (71.8m points)

c# - Update ObservableCollection when Firestore event occurs

I am trying to use Xamarin Forms to create a cross-platform application. I have decided to use Firestore as the database for my app.

I am trying to add chat functionality to my app using and I'm struggling with implementing the real-time listening functionality. I have already created a ViewModel class containing an ObservableCollection of Chats that is used by a ListView in the UI.

public class ChatsVM
{
    public ObservableCollection<Chat> Chats { get; set; }

    public ChatsVM()
    {
        Chats = new ObservableCollection<Chat>();
        ReadMessages();
    }

    public async void ReadMessages()
    {
        User currentUser = await DependencyService.Get<IFirebaseAuthenticationService>().GetCurrentUserProfileAsync();
        IList<Chat> chatList = await DependencyService.Get<IChatService>().GetChatsForUserAndListenAsync(currentUser.IsLandlord, currentUser.Id);

        foreach (var chat in chatList)
        {
            Chats.Add(chat);
        }
    }
}

I have also created the services to fetch the data from Firestore. On the service side of things (example is showing Android service) I am using a standard List to hold Chat objects

List<Chat> Chats;
bool hasReadChats;

The method GetChatsForUserAndListenAsync adds a snapshot listener to my query and passes events to the OnEvent method.

public async Task<IList<Chat>> GetChatsForUserAndListenAsync(bool isLandlord, string userId)
    {
        string fieldToSearch;

        if (isLandlord)
        {
            fieldToSearch = "landlordId";
        }
        else
        {
            fieldToSearch = "tenantId";
        }

        try
        {
            // Reset the hasReadChats value.
            hasReadChats = false;
            CollectionReference collectionReference = FirebaseFirestore.Instance.Collection(Constants.Chats);
            // Get all documents in the collection and attach a OnCompleteListener to
            // provide a callback function.
            collectionReference.WhereEqualTo(fieldToSearch, userId).AddSnapshotListener(this);

            // Wait until the callback has finished reading and formatting the returned
            // documents.
            for (int i = 0; i < 10; i++)
            {
                await System.Threading.Tasks.Task.Delay(100);
                // If the callback has finished, continue rest of the execution.
                if (hasReadChats)
                {
                    break;
                }
            }

            return Chats;
        }
        catch (FirebaseFirestoreException ex)
        {
            throw new Exception(ex.Message);
        }
        catch (Exception)
        {
            throw new Exception("An unknown error occurred. Please try again.");
        }
    }

public void OnEvent(Java.Lang.Object value, FirebaseFirestoreException error)
    {
        var snapshot = (QuerySnapshot) value;

        if (!snapshot.IsEmpty)
        {
            var documents = snapshot.Documents;
            Chats.Clear();

            foreach (var document in documents)
            {
                Chat chat = new Chat
                {
                    Id = document.Id,
                    LandlordId = document.Get("landlordId") != null ? document.Get("landlordId").ToString() : "",
                    TenantId = document.Get("tenantId") != null ? document.Get("tenantId").ToString() : ""
                };
                //JavaList messageList = (JavaList) document.Get("messages");
                //List<Message> messages = new List<Message>();

                // chat.Messages = messages;

                Chats.Add(chat);
            }
            hasReadChats = true;
        }
    }

How would I propagate any changes to this list that are made by the event handler to the ObservableCollection in my VM class?

question from:https://stackoverflow.com/questions/66053387/update-observablecollection-when-firestore-event-occurs

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Credit to Jason for suggesting this answer.

So I modified the event handler to look for document changes in Firestore. Based on these changes, the service would send different messages using MessagingCenter.

public async void OnEvent(Java.Lang.Object value, FirebaseFirestoreException error)
    {
        var snapshot = (QuerySnapshot) value;

        if (!snapshot.IsEmpty)
        {
            var documentChanges = snapshot.DocumentChanges;
            IFirebaseAuthenticationService firebaseAuthenticationService = DependencyService.Get<IFirebaseAuthenticationService>();
            Chats.Clear();
            
            foreach (var documentChange in documentChanges)
            {
                var document = documentChange.Document;
        
                string memberOne = document.Get(Constants.MemberOne) != null ? document.Get(Constants.MemberOne).ToString() : "";
                string memberTwo = document.Get(Constants.MemberTwo) != null ? document.Get(Constants.MemberTwo).ToString() : "";
                
                Chat chat = new Chat
                {
                    Id = document.Id,
                    MemberOne = memberOne,
                    MemberTwo = memberTwo,
                };

                var documentType = documentChange.GetType().ToString();

                switch (documentType)
                {
                    case Constants.Added:
                        MessagingCenter.Send<IChatService, Chat>(this, Constants.Added, chat);
                        break;
                    case Constants.Modified:
                        MessagingCenter.Send<IChatService, Chat>(this, Constants.Modified, chat);
                        break;
                    case Constants.Removed:
                        MessagingCenter.Send<IChatService, Chat>(this, Constants.Removed, chat);
                        break;
                    default:
                        break;
                }
               
                Chats.Add(chat);
            }
            hasReadChats = true;
        }
    }

In the constructor for the VM, I subscribed as a listener for these messages and updated the ObservableCollection accordingly.

public class ChatsVM
{
    public ObservableCollection<Chat> Chats { get; set; }

    public ChatsVM()
    {
        Chats = new ObservableCollection<Chat>();
        ReadChats();
    }

    public async void ReadChats()
    {
        IFirebaseAuthenticationService firebaseAuthenticationService = DependencyService.Get<IFirebaseAuthenticationService>();

        MessagingCenter.Subscribe<IChatService, Chat>(this, Constants.Added, (sender, args) =>
        {
            Chat chat = args;
            Chats.Add(chat);
        });

        MessagingCenter.Subscribe<IChatService, Chat>(this, Constants.Modified, (sender, args) =>
        {
            Chat updatedChat = args;
            Chats.Any(chat =>
            {
                if (chat.Id.Equals(updatedChat.Id))
                {
                    int oldIndex = Chats.IndexOf(chat);
                    Chats.Move(oldIndex, 0);
                    return true;
                }
                return false;
            });
        });

        MessagingCenter.Subscribe<IChatService, Chat>(this, Constants.Removed, (sender, args) =>
        {
            Chat removedChat = args;
            Chats.Any(chat =>
            {
                if (chat.Id.Equals(removedChat.Id))
                {
                    Chats.Remove(chat);
                    return true;
                }
                return false;
            });
        });
        
        User currentUser = await firebaseAuthenticationService.GetCurrentUserProfileAsync();
        await DependencyService.Get<IChatService>().GetChatsForUserAndListenAsync(currentUser.Id);
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...