how to do Shell Navigation with complex objects in .net MAUI or Xamarin Forms?

Viewed 659

Recently I've started using shell and I noticed an improvement in page transitioning and a bug I was facing using NavigationPage was fixed just by replacing it with shell.

So I was excited to use it.

However soon after I realized I can't send objects from page to page through shell like I could using a constructer of a page. I searched a bit and now know that shell passes strings only. I turned the object into JSON but then faced an exception due to long URI length.

Honestly, I am disappointed. I thought something this important would be implemented in shell... but In any case, how do you guys work around this?

1 Answers

For Maui.

See (Xamarin) Process navigation data using a single method.

Also mentioned in maui issue. Adapting the Maui invocation there:

await Shell.Current.GoToAsync("//myAwesomeUri",
    new Dictionary { {"data", new MyData(...)} });

This uses IQueryAttributable and ApplyQueryAttributes to pass an IDictionary<string, object> query.
(The Xamarin example shows IDictionary<string, string>, but its , object in Maui, so you can pass any object values.)

Thus the string parameters you pass can be used to look up corresponding objects.

From that (Xamarin) doc (modified to show looking up an object):

public class MonkeyDetailViewModel : IQueryAttributable, ...
{
    public MyData Data { get; private set; }

    public void ApplyQueryAttributes(IDictionary<string, object> query)
    {
        Data = (MyData)query["data"];
    }
    ...
}

For Xamarin Forms, the limitation to string values makes this a bit ugly. One approach is to have a static that holds possible objects, which you look up using a string. This is tolerable when the objects are all pre-defined, but is a bit clumsy if you are manually altering those objects.

public class MonkeyDetailViewModel : IQueryAttributable, ...
{
    public static Dictionary<string, MyData> KeyedData;

    // "static": One-time class constructor.
    public static MonkeyDetailViewModel()
    {
        KeyedData = new Dictionary<string, MyData>();
        KeyedData["data1"] = new MyData(...);
        // ... other versions of the data ...
    }


    public MyData Data { get; private set; }

    public void ApplyQueryAttributes(IDictionary<string, string> query)
    {
        string whichData = query["data"];   // In example, gets "data1".
        Data = KeyedData[whichData];
    }
    ...
}

Usage:

await Shell.Current.GoToAsync("//myAwesomeUri",
    new Dictionary { {"data", "data1"} });

Xamarin NOTE: The static dictionary makes it possible to maintain multiple instances of MyData. The "hack" alternative is to have MyData Data be static, and explicitly set it before GoToAsync - but this is risky if you ever might have a MonkeyDetailView on nav stack, go to a second one, then go back to first one - you'll have overwritten the Data seen by the first view.

Related