If you are annoyed by the aspect of updating the data stored in the models, and you think about how great it would be if the model could be more independent and notify about changes, welcome to cat.
Note. Further, the story will be conducted on behalf of the author.As a .NET developer, I’m partial to MVVM and data binding. Thanks to them, I can untie ideas from application logic, and, in most cases, write an application without having to worry about updating the user interface. However, one annoying aspect remains - updating the data stored in the models. Most often, I get a network call that takes certain data, stores it on disk, and then updates the view models by wrapping the corresponding model, whether by comparing changes or updating the entire interface. But it would be great if the model could take care of this independently and notify us about the changes, wouldn’t it? It turns out that when using
Realm for long-term data storage, this becomes possible.
')
This may come as a surprise to some, but all objects stored in the Realm are initially available for observation. And even including functional dependencies and query results! And because of this, it is extremely easy to transfer them directly to data binding. In this post, I’ll focus on Xamarin.Forms, because they come with a data-binding-friendly visualization engine, but you can easily use a project with a native UI with frameworks such as
MvvmCross and
MVVM Light . So let's take a look at an example of how using Realm, you can create a very simple contact application with it.
Models
Since we do not want to complicate anything here, let's define only one model class - User:
public class User : RealmObject { public string Id { get; set; } = Guid.NewGuid().ToString(); public string Name { get; set; } }
Here we specify the saved object, which, thanks to Realm, will be constantly updated. So, as soon as you have an instance of the
User
class, there is no need to “update” it, because whenever you access the property, the current information is saved. In addition,
RealmObject
implements
INotifyPropertyChanged
, which allows you to subscribe and receive notifications about any possible changes. And although these are just a few lines of code, their impact is very significant. And even better, there are actually no templates here - there is no manual triggering of the event, SQL mapping, and, of course, the update logic.
List of contacts
First of all, the contacts application is expected to have the functionality to display, as a matter of fact, a list of contacts. In the MVVM world, this usually means providing an
ObservableCollection<User>
in a
ViewModel
, linking it, and then updating when models are changed (for example, after adding a new contact). It sounds like it is very difficult, but look at how we will cope with this task with the help of Realm:
public class ContactsViewModel { private readonly Realm _realm; public IEnumerable<User> Users { get; } public ContactsViewModel() { _realm = Realm.GetInstance(); Users = _realm.All<User>().OrderBy(u => u.Name); } }
And here is our page (we have to set the
ContactsViewModel
in the code as a
BindingContext
, but there’s nothing interesting there, so let's just assume that we did it):
<ContentPage x:Class="Contacts.ContactsPage"> <ContentPage.Content> <ListView ItemsSource="{Binding Users}" x:Name="ContactsListView"> <ListView.ItemTemplate> <DataTemplate> <ViewCell> <Label Text="{Binding Name}"/> </ViewCell> </DataTemplate> </ListView.ItemTemplate> </ListView> </ContentPage.Content> </ContentPage>
And here is the result! One-time initialization - and manual updating of
Users
no longer required. The runtime type of the collection returned by
Realm.All implements
INotifyCollectionChanged , which is monitored by the Xamarin Forms data binding mechanism, so that the interface is notified of any changes that occur in the collection. When working with a native UI project, you can either convert this type yourself, or use the
AsRealmCollection extension
method . Now, in confirmation of my words, let's consider how we can make certain changes.
Editing a single contact
public class EditContactViewModel { public User User { get; } public EditContactViewModel(User user) { User = user; } }
And the corresponding page:
<ContentPage x:Class="Contacts.EditContactPage" Title="{Binding User.Name}"> <ContentPage.Content> <Entry Text="{Binding User.Name}" Placeholder="Contact name" /> </ContentPage.Content> </ContentPage>
From the moment the
Entry
bindings become bidirectional by default, whenever you change a username, the change is saved to disk and the page title is updated. And since our ListView on the main screen is associated with an “active” query, it will update the relevant new data already by pressing the “back” button. Connecting navigation to view models is not so fun, so I will not dwell on this here. But with one of the ways to do this can be found in the
finished example .
Add contact to favorites
Let's expand a bit the functionality of our “raw” application so far, that is, we add the ability to mark a contact as a favorite. First, add a new property to our User:
public class User : RealmObject { public bool IsFavorite { get; set; } }
After that, we update the
ContactsViewModel
so that the selected contacts are shown above, and also add the command “Switch favorites”:
public class ContactsViewModel { public Command<User> ToggleIsFavoriteCommand { get; } public ContactsViewModel() { _realm = Realm.GetInstance(); Users = _realm.All<User>().OrderByDescending(u => u.IsFavorite) .ThenBy(u => u.Name); ToggleIsFavoriteCommand = new Command<User>(user => { _realm.Write(() => user.IsFavorite = !user.IsFavorite); }); } }
Due to this, the selected contacts will rise up, but, moreover, both groups will still be distributed in alphabetical order. And finally, let's add the ☆ button to our element (if you are interested in alternating the ☆ and ★ buttons depending on whether the contact is added to your favorites or not, see the
ready example ):
<ViewCell> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="*" /> <ColumnDefinition Width="60" /> </Grid.ColumnDefinitions> </Grid> <Label Text="{Binding Name}"/> <Button Text="☆" Grid.Column="1" Command="{Binding Path=BindingContext.ToggleIsFavoriteCommand, Source={x:Reference Name=ContactsListView}}" CommandParameter="{Binding .}"/> </ViewCell>
That's all. Nothing supernatural, of course, but in this way we were able to clearly demonstrate the extent to which it is easier to add new functions when models are available for observation and are constantly updated.

Possible performance implications
This question constantly emerges when it comes to observable and active objects - “How do they affect performance?” Of course, nothing comes for free. And the ability to monitor changes is no exception. So for using this function, you have to pay a small premium in resource consumption. The good news is that this change watch only happens when you subscribe to
PropertyChanged
or
CollectionChanged
and stop as soon as the subscription stops. This means that if you have a million objects processed and you do not want to receive notifications about them, then the possibility of observing
RealmObjects
will not in any way affect you. And if you care about changes and use
RealmObjects
for data binding, then the slowdown caused by notifications will be negligible compared to the logic of data binding and layout calculations that are performed by Xamarin Forms with each update.
Conclusion
Realm allows you to easily develop the user interface of the application based on the data on the disk. Thanks to this, it is possible to develop truly capacious offline applications. And also, more importantly, create a user interface that will be independent of where the model changes occur. They can be the result of a user action, a web request, or even synchronization with a server through the
Realm Mobile Platform (which will
very soon join Xamarin services). And no matter what the result they will be - the user will see each update as soon as it appears.
If you have a few minutes left,
take a look and
pick up the database (it was created on the basis of open source code and is available for free). Or if you are like me and like to play with a ready-made project, before reading blog posts, get the code on
GitHub .
Thank you for the translation.
Alexander Alekseev - Xamarin-developer, freelancer. Works with the .NET platform since 2012. Participated in the development of a procurement automation system at Digamma. C 2015 went into freelancing and switched to mobile development using Xamarin. Currently working at StecPoint on an iOS application.
It
manages the XamDev.ru resource and the Xamarin Developers community in social networks:
VK ,
Facebook ,
Telegram .
Other articles from our Xamarin blog can be found at #xamarincolumn .