Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UWP: The view is not in sync with the database. #1759

Closed
Mohsens22 opened this issue Jul 21, 2018 · 16 comments · Fixed by #3150
Closed

UWP: The view is not in sync with the database. #1759

Mohsens22 opened this issue Jul 21, 2018 · 16 comments · Fixed by #3150
Assignees

Comments

@Mohsens22
Copy link

Mohsens22 commented Jul 21, 2018

Goals

Hello. I'm getting started with Realm platform to make an application in sync.

The problem is that the data in my view does not become synced with db and I need to fetch it again.

Expected Results

I want to add a data to database and I want the data list to be in sync with DB.
I bonded the ListView to an IRealmCollection.

Actual Results

When I add the data in the db using

var todo = new Todo()
            {
                Id = DateTime.UtcNow.Ticks.ToString(),
                Subject = DateTime.Now.ToString(),
                Detail = Details.Text,
                Status = 2
            };
            RealmContext.Instance.Write(() =>
            {
                RealmContext.Instance.Add(todo);
            });

it saves successfully but the point is that UI does not update itself with newly added data; so I need to fetch the data again with RealmContext.Instance.All<Todo>().AsRealmCollection(); which is not what I want. When I subscribe to changes via

TodayList.CollectionChanged += (s, e) =>
            {
                foreach (var item in TodayList)
                {
                    Debug.WriteLine(item.Subject);
                }
            };

the fun fact is that it is not triggered when I insert my first data into the db. it triggers second time.
Even more fun is this, the VS debug output shows all items that I've added except the one that it didn't trigger this event !!! Please help.

Code Sample

You can take a look at the project that I'm working on at HERE

In the core project there are everything related to the Database.
Also TimelineViewModel.cs file is related to the issue.

image

Views>Add>Task.xaml is for adding an item to DB.

Version of Realm and Tooling

  • Realm Object Server Version: Last version. On the cloud
  • Client SDK Version: Windows 10 SDK 17134
  • Client OS & Version: 3.1.0
@Mohsens22
Copy link
Author

To implify things, I have made another test project that you can use to duplicate the issue in your environment:
MainPage.xaml

<Page
    x:Class="ReactiveUI.MainPage"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:ReactiveUI"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">

    <StackPanel>

        <Button Content="Login" Width="400" Height="40" Click="Button_Click_1" />
        <Button Content="Initialize" Width="400" Height="40" Click="Button_Click_2" />
        <Button Content="Add" Width="400" Height="40" Click="Button_Click" />
        <ListView x:Name="itemListView" ItemsSource="{x:Bind TodayList}"/>
    </StackPanel>
</Page>

MainPage.xaml.cs

using Realms;
using Realms.Sync;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Foundation;
using Windows.Foundation.Collections;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Controls.Primitives;
using Windows.UI.Xaml.Data;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=402352&clcid=0x409

namespace ReactiveUI
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        public Realm Instance;
        public MainPage()
        {
            this.InitializeComponent();
        }
        public IRealmCollection<Todo> TodayList { get; set; }

        protected override void OnNavigatedTo(NavigationEventArgs e)
        {
            base.OnNavigatedTo(e);
            var configuration = new FullSyncConfiguration(new Uri("~/myRealm", UriKind.Relative));
            Instance = Realm.GetInstance(configuration);
            TodayList = Instance.All<Todo>().AsRealmCollection();
        }

        private void Button_Click(object sender, RoutedEventArgs e)
        {
            var todo = new Todo()
            {
                Id = DateTime.UtcNow.Ticks.ToString(),
                Subject = DateTime.Now.ToString(),
                Status = 2
            };
            Instance.Write(() =>
            {
                Instance.Add(todo);
            });
        }

        private async void Button_Click_1(object sender, RoutedEventArgs e)
        {
            var credentials = Credentials.UsernamePassword("mohsens22", "test", createUser: false);
            var user = await User.LoginAsync(credentials, new Uri("https://denna.de1a.cloud.realm.io/"));
            User.ConfigurePersistence(UserPersistenceMode.Encrypted);
        }

        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            var configuration = new FullSyncConfiguration(new Uri("~/myRealm", UriKind.Relative));
            Instance = Realm.GetInstance(configuration);
        }
    }
    public class Todo : RealmObject
    {
        [PrimaryKey]
        public string Id { get; set; }
        public string Subject { get; set; }
        public string Detail { get; set; }
        public int Notify { get; set; }
        public int Status { get; set; }
        public DateTimeOffset StartTime { get; set; }
        public DateTimeOffset EndTime { get; set; }
        public int Imprtance { get; set; }

    }
}

Note that the UI is not reactive and it's not in sync with the database.

@nirinchev
Copy link
Member

This is somewhat unfortunate, but it's a decision that we made - the reason it doesn't automatically update listviews is that UWP needs the runtime representation of the collection to implement IList. This is not a problem in of itself, but Xamarin.Android has a bug where if a collection implements IList, the app freezes when deselecting items - #1575.

So we had to choose to either support databinding in collections for UWP or Xamarin.Android and we chose the latter. Still, because the change was made with Realm 3.1.0, you can downgrade to 3.0.0 which should still work with UWP. Hope this helps.

@Mohsens22
Copy link
Author

Nicely works on realm 3.0
But my advice is that to fix this UWP thing. I can help you with that if you want.

@Mohsens22
Copy link
Author

Also tag this with bug.

@nirinchev
Copy link
Member

It's an either-or situation - either we fix it and it works on UWP or we don't and it works on Xamarin.Android. Currently, we have many more users on Android which is why we decided to take that path.

@Mohsens22
Copy link
Author

I used to contribute on couchbase. They had similar issue. They decided to make support packages for each platform and inject platform-specific implementations to their code via "Dependency Injection" You could go that way or make a separate .UWP package inducing a hotfix.

@Mohsens22
Copy link
Author

Also there is another bug in 3.0
When I delete something, it just changes the order (but deletes in database)
So I need to fetch database again to have them in correct order
Fix em PLEASE

@nirinchev
Copy link
Member

The order of items in the database is not fixed and deletes can rearrange that. For example, if you delete the item in position X, the last item in the table moves to its place to avoid fragmenting the storage. If you want your view to display them in particular order, you need to sort the table, e.g. TodayList = Instance.All<Todo>().OrderBy(o => o.Name).

And while compiling platform-specific packages is something we've considered in the past, the maturity of the tooling at the time prevented us from pursuing this avenue.

@Mohsens22
Copy link
Author

What's your plan for fixing these platform issues?

@nirinchev
Copy link
Member

It's one issue with a simple workaround, that affects a small number of users, and is not part of the core functionality. That's why, it's not very high on our priority list and unless a paying customer requests a fix for it, I don't expect we'll look into it before Q1/2019.

@Mohsens22
Copy link
Author

Mohsens22 commented Aug 2, 2018

I'm going to fix and make a Realm.UWP package for now. But I await your fix for all platforms.

UPDATE:
https://www.nuget.org/packages/Realm.UWP/3.1.0
https://github.com/Mohsens22/realm-dotnet

@BergHeisen
Copy link

It's one issue with a simple workaround, that affects a small number of users, and is not part of the core functionality. That's why, it's not very high on our priority list and unless a paying customer requests a fix for it, I don't expect we'll look into it before Q1/2019.

Has it been completly abondoned as Idea?

@nirinchev
Copy link
Member

Sorry for the late response - I think I have a workaround that doesn't crash the latest Xamarin.Forms.

@nirinchev nirinchev self-assigned this Jan 5, 2023
@BergHeisen
Copy link

Sorry for the late response - I think I have a workaround that doesn't crash the latest Xamarin.Forms.

So Items added to the list through Flex Sync, do not get automatically added to the List. If it's done locally, it updates.
Removing does not update locally nor through flex sync.
Editing works, locally and through flex sync.

This is my RealmObject

public sealed class PasswordGroup : RealmObject
    {
        [PrimaryKey]
        [MapTo("_id")]
        public ObjectId Id { get; set; } = ObjectId.GenerateNewId();

        [MapTo("passwords")]
        public IList<PasswordData> Passwords { get; }

        [MapTo("ownerId")]
        [Required]
        public string OwnerId { get; set; }
    }

And I currently applying it to the ListView like so

var binding = new Binding();
binding.Source = Database.PasswordGroup.Passwords.OrderBy(p => p.Website);
binding.Mode = BindingMode.OneWay;
PasswordListView.SetBinding(ListView.ItemsSourceProperty, binding);

@nirinchev
Copy link
Member

I believe the issue is that you're applying an ordering to the Passwords list, which snapshots the collection (i.e. it is no longer live). You can confirm that by trying to cast Database.PasswordGroup.Passwords.OrderBy(p => p.Website) as INotifyCollectionChanged - I'm fairly certain that'll give you null.

If you want to preserve the collection as a live collection emitting notifications, you need to construct a query and apply the ordering on top of that (note that you'll be limited by the sorting capabilities of the database, though a simple sort like that will work just fine). I haven't tested it, but I think something like this would work:

binding.Source = Database.PasswordGroup.Passwords.AsRealmQueryable().OrderBy(p => p.Website);

This will convert the list to a query and execute the sort at the database level, thus preserving change notification capabilities.

@BergHeisen
Copy link

I believe the issue is that you're applying an ordering to the Passwords list, which snapshots the collection (i.e. it is no longer live). You can confirm that by trying to cast Database.PasswordGroup.Passwords.OrderBy(p => p.Website) as INotifyCollectionChanged - I'm fairly certain that'll give you null.

If you want to preserve the collection as a live collection emitting notifications, you need to construct a query and apply the ordering on top of that (note that you'll be limited by the sorting capabilities of the database, though a simple sort like that will work just fine). I haven't tested it, but I think something like this would work:

binding.Source = Database.PasswordGroup.Passwords.AsRealmQueryable().OrderBy(p => p.Website);

This did indeed work, thanks a lot !

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Mar 12, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants