Xamarin.Forms Shell

Can we get an example Xamarin.Forms sample application using Shell Navigation? (Or .NET MAUI preview). I put together a sample application for a local meetup, but I am sure there is a more elegant implementation.

Thank you

Hi @difschultz, you are right, at the moment we do not have an example application that uses Shell Navigation. From what I have been reading about Shell, it seems simplify the navigation part of the app, and so that should not influence the way that Realm is used.
Regarding an example with .NET MAUI, that is something that for sure we are going to work on in the near future, closer to the official release.

As a side note, I have given a very brief look to your project and I can think I can give you a suggestion. You do not need to authenticate the user (App.RealmApp.LogInAsync(Credentials.ApiKey(App.adminAKey)) again every time you need to get a Realm instance. You can just do it once when you start the app and then you’re done. Also, if you are using Realm only from the main thread, you can create a singleton realm instance that you can access from everywhere. This should remove some duplicated code from your application.
Additionally I could suggest to take a look at a presentation from some months ago here about some best practices on how to use Realm with Xamarin.Forms, including how to work with threads (the first half is mostly a presentation of Forms, so you can skip it).
Feel free to write if you have additional questions

Hello @papafe, thank you for the link to the presentation. Basically, the issue with Shell navigation is that I was not able to pass the Realm Object from one MVVM View to the Next like we were able to do using Brian and Dan’s Prism Library. If we are passing the Guid, for example, to a DetailsView it would be helpful to have the correct place in the page lifecycle to work with the Realm Object.

@difschultz now I see your point! Now that I know what was the problem I can take a look and see what I can do.

Hi @difschultz, I have been reading a little bit more about Shell, because I did not have any first hand experience with it.
I can see that due to the route based navigation it’s not passible to pass objects between pages (like with Peism), but only strings. For this reason it makes sense to pass the guid of the object one needs to display in the detail page for instance, and then use realm to retrieve it. I am not sure if I understand your point about the “correct place in the lifecycle to work with the Realm Object”. From what I could see with your project methods like “LoadWineId” and “LoadDishId” seems to be good places where to retrieve realm objects, as you’re already doing. As I said before obviously the code can be simplified if you use a singleton realm instance, but that’s another story.
As another side note, you could also bind the UI directly to the realm object, so you wouldn’t even need to create a new variable.
Feel free to send me an example to make me understand better in case I missed something. As I have said I do not have much experience with Shell so I could be missing something obvious.

Hello Ferdinando, yes you are on the right track. I am sure in .NET MAUI the page behavior will be a little less magical than Xamarin.Forms. Prism provided these stubs that worked well with RealmObject.

async void OnNavigatedTo(INavigationParameters parameters)

async void OnNavigatedFrom(INavigationParameters parameters)

One of the issues I noticed with Shell Navigation is that LoadRealmObjectId works when the QueryPropertyAttribute was set in the detail page, but when no such mechanism exists in the collection page.

That is where I got stuck and do not have an example binding the UI directly to the realm object with the transaction set correctly. Feel free to send me the design pattern if you get to it first!

Have a great time!

Regarding the binding, we are actually in the process of updating one of the examples that are in the github repository of Realm .NET. If you want to take a look at how the binding is done you can look here, but obviously this is still a work in progress.
But the main idea is that in the ViewModel you expose a RealmObject, and then you can bind to it in the UI.
For instance:

public class Contact : RealmObject
{
    public string FullName { get; set; }
    public string Nickname { get; set; }
    public string Address { get; set; }
    public string Company { get; set; }
}

In the ViewModel:

    public Contact Contact { get; private set; }

In the Xaml file:

    <Entry Text="{Binding Contact.FullName}" IsSpellCheckEnabled="False" />

And the good thing with this approach is that if any of the bound property on the Contact changes (like the FullName in this case), the UI gets automatically updated. The binding can be also bidirectional, so every change in the UI will be reflected in the RealmObject. There’s some magic done in the background, so you don’t need to worry about transactions if you use bindings :slight_smile:
Regarding Shell, let me take a look. I wanted to write you first about the binding to not keep you waiting

Regarding Shell, I’m sorry, I am not getting what you’re trying to do.
Can you maybe copy here some code from your project to make me understand what does not work?

Hello @papafe,

One of the issues the simple CRUD application above has is that the WineCollectionPage requires clicking the Refresh button in the toolbar to display the Wine Collection. The CollectionView should render the wines when the page loads. I have not tried to bind the CollectionView through XAML yet.

LoadWinesCommand = new Command(async () => await ExecuteLoadWinesCommand());

When navigating to the UpsertWinePage with WineId, the QueryProperty retrieves the value passed and sets the page WineId property which magically renders the wine name correctly.

[QueryProperty(nameof(WineId), nameof(WineId))]

 private string wineId;
 public string WineId
 {
 	get
    {
    	return wineId;
    }
    set
    {
             wineId = value;
             LoadWineId(value);
    }
 }

Microsoft Shell Navigation

Because the wine collection page does not have the QueryProperty attribute, the page developer needs the recipe to know where in the page lifecycle to query the data and bind the UI control (when using code behind). Having a set OnNavigatingTo with Prism MVVM provided consistent output across all platforms that worked.

Now I see your point. So, the issue here is that you do not have lifecycle methods like OnAppearing and OnDisappearing in your ViewModel, so you do not know when to load the page. This is a generic Xamarin.Forms issue, more than a Realm one, but I can give you an example of how to solve it.
So, what I normally do is to have a BaseViewModel class that all other ViewModel derive to that looks like this:

public class BaseViewModel
{
    ....
    public virtual void OnAppearing() { }

    public virtual void OnDisappearing() { }
}

Then a BasePage that looks like this:

public class BasePage : ContentPage
{
    protected override void OnAppearing()
    {
        base.OnAppearing();
        (BindingContext as BaseViewModel)?.OnAppearing();
    }

    protected override void OnDisappearing()
    {
        base.OnDisappearing();
        (BindingContext as BaseViewModel)?.OnDisappearing();
    }
}

This way in your specific ViewModel you can override OnAppearing and OnDisappearing and do what you need to do when the page appears :slight_smile:

Even though that would definitely work, if you use the bindings as I’ve suggested before (binding the wine collection to the UI), you wouldn’t even need to do anything when the page appears, as Realm will take care of notifying the UI that something has changed, and you don’t need to do it yourself. If you look at this example here you can take a look at how it’s done in JournalEntriesViewModel with the Entries collection.

1 Like