Realm with ReactiveUI


#1

I have a sample app using realm with ReactiveUI. The UI is based on Xamarin.Forms. The app allow to add items to a collection and filter them according to search term. The issue is that when I add new item it does not show in the listview. But when I restart the app it shows up. The filtered list is shown correctly according to the search term.
I didn’t understand why the listview stopped updating new items after I added the filter logic for searching items. The ViewModel Code is:

public class MainViewModel : ReactiveObject
{

    public IEnumerable<Company> Companies { get; set; }

    [Reactive]
    public string Query { get; set; }


    [Reactive]
    public string NewCompany { get; set; }

    public ReactiveCommand<Unit, Unit> AddCompanyCommand { get; set; }
    public ReactiveCommand<Unit, IEnumerable<Company>> SearchCommand { get; set; }

    Realm _realm;

    public MainViewModel()
    {

        _realm = Realm.GetInstance();

        Companies = _realm.All<Company>();

        AddCompanyCommand = ReactiveCommand.CreateFromTask(async () => await AddButtonClicked());
        SearchCommand = ReactiveCommand.Create<Unit, IEnumerable<Company>>(
            _ =>

            SortCollection()
            );


        SearchCommand.ToProperty(this, nameof(Companies));

        this.WhenAnyValue(x => x.Query).Throttle(TimeSpan.FromSeconds(1)).Select(_ => Unit.Default).InvokeCommand(this, x => x.SearchCommand);


    }

    async Task AddButtonClicked()
    {
        if (!string.IsNullOrWhiteSpace(NewCompany))
        {
            _realm.Write(() =>
            {
                _realm.Add(new Company { Name = NewCompany });
            });
            NewCompany = string.Empty;
        }
    }

    IEnumerable<Company> SortCollection()
    {
        if (string.IsNullOrWhiteSpace(Query))
        {
            Companies = Companies.Where(x => x.Name != string.Empty);
        }
        else
        {
            Companies = Companies.Where(x => x.Name.IndexOf(Query, StringComparison.InvariantCultureIgnoreCase) >= 0);
        }

        return Companies;


    }

}

#2

What platform are you running this on?


#3

I am running this on iOS and Android. Replying so late because I was unable to login due to some technical reason.


#4

Looks like the problem is that you’re returning IEnumerable from SortCollection. The LINQ engine will not try to cast it as IQueryable, so the filter is executed in memory, not at the database level. You can fix that by changing the type of the Companies property to IQueryable<Company>.


#5

Thank you for the answer. The list is updated in real time with IQueryable. But now the list is not showing filtered results.


#6

When I set breakpoint where the SortCollection returns Companies the count of the items show:
System.Exception: Realm accessed from incorrect thread.
Further if I try to short the Items from database the app crashes.


#7

If the Realm was opened on the main thread, you need to configure the RX to use the synchronization context of the main thread to ensure that any work is dispatched back on it.


#8

But why the ListView only shows SearchResults with IEnumerable and not newly added items. Whereas when I used IQueryable the ListView shows new added items but not SearchResults.


#9

As I already said, it looks like the invocation of the Search command happens on a different thread than the one the Realm was originally created on. This means that an exception is thrown when trying to further filter the collection, which I guess RX handles internally. You need to either configure SearchCommand to marshal filtering back to the main thread or setup the RX synchronization context to the one from the main thread to ensure that the commands are always executed on the main thread.