The Miracle of IQueryAttributable

This knocked me out. Let’s say you have a value in one view model, and when you navigate to another page you want that value in the new page’s view model. Enter IQueryAttributable. (tough to say, even tougher to spell)

I have created a simple example. We’re going to start with an out of the box Xamarin.Forms project. As part of that we’ll get an AboutPage. At the bottom of the about page I’m going to add a button:

<Button Text="ShowId" Command="{Binding ShowIdCommand}" />

Nothing surprising here. Let’s follow that ShowIdCommand. For that we turn to the associated view model (also out of the box)

I’m going to add important data to the code behind: in this case an id whose value is “123”

I’m then going to add the Command ShowIdCommand which will invoke the ShowId method

private string id = "123";

public AboutViewModel()
{
    Title="About";
}

private ICommand _showIdCommand;

public ICommand ShowIdCommand => _showIdCommand??(_showIdCommand=
    new Command(async param => await ShowId()));


(Note that I’ve removed the OpenWebCommand that normally comes with this file to keep things uncluttered.)

Now comes part one of the magic. I’ll use Shell navigation to go to a new page, but I’ll pass in the Id as a paramter. Note, I can name that parameter anything I like, in this case I’ll name it QueryId

protected async Task ShowId()
{
    await Shell.Current.GoToAsync($"{nameof(MyNewPage)}?QueryId={id}");
}

We travel now to MyNewPage, but not to the code behind (yuck) but rather to the view model (yay!)

The first requirement is that you mark your view model as implementing IQueryAttributable

Next, create a local property Id. This you will fill from the parameter you passed in. To do that (and to fulfill the IQueryable interface) you add a method named ApplyQueryAttributes. This method’s parameter will be a dictionary which will be provided for you by magic. You do not have to fill the dictionary.

public void ApplyQueryAttributes(IDictionary<string, string> query)
{
    if (query.ContainsKey("QueryId"))
    {
        _id=HttpUtility.UrlDecode(query["QueryId"]);
    }
}

We simply check to see if the dictionary has a key matching the key we sent as a parameter, and if so we can extract the value (Id) and do whatever we like with it (in this case, I’m stashing it away in a local field). You can, of course, check for as many parameters as you like.

I was so impressed by this I had to tell you.

About Jesse Liberty

Jesse Liberty has three decades of experience writing and delivering software projects and is the author of 2 dozen books and a couple dozen online courses. His latest book, Building APIs with .NET will be released early in 2025. Liberty is a Senior SW Engineer for CNH and he was a Senior Technical Evangelist for Microsoft, a Distinguished Software Engineer for AT&T, a VP for Information Services for Citibank and a Software Architect for PBS. He is a Microsoft MVP.
This entry was posted in Essentials. Bookmark the permalink.