7

I have my main page and in this page I have a list with objects. With a foreach I get the items of it and I want to pass the item to another page if you click the button. How can I pass it?

3
  • Do a bit of searching for Blazor Application State - This is a good introduction. There are many ways to handle state in Blazor - you can choose which way suits your project. Commented Jul 7, 2021 at 8:37
  • As your question is a bit thin on code, I would suggest you need to use a scoped service to hold a collection of the objects, probably an IDictionary with an integer key you pass to the new page - newpage/1. NewPage then uses 1 to retrieve the specific object. from the service. See the MSDocs about services - learn.microsoft.com/en-us/aspnet/core/blazor/fundamentals/… Commented Jul 7, 2021 at 8:38
  • 1
    The easiest answer is-- don't navigate. I recommend only navigating to move to a separate section of the app (i.e. which doesn't need to pass any data). Show a control that displays your item. Commented Jul 7, 2021 at 9:02

2 Answers 2

16

Regarding more complex objects it is good to use StateContainer (in memory solution).

Register your StateContainer in MauiProgram.cs like:

builder.Services.AddScoped<StateContainer>(); 

where StateContainer.cs contains:

public readonly Dictionary<int, object> ObjectTunnel = new(); 

then just as an example I will create ComplexObject.cs where

public class ComplexObject { public int Count = 0; public string Color = string.Empty; } 

then when you have pages e.g. Index.razor and Counter.razor and you would like to send ComplexObject from one the the other, then in Index.razor inject StateContainer

and call something like:

public void OpenCounterWithData() { var data = new ComplexObject{Count = 3, Color="red"} _stateContainer.ObjectTunnel.Add(data.GetHashCode(), data) _navigationManager.Navigate($"counter/{data.GetHashCode()}") } 

and In Counter.razor you specify page like:

@page "/counter/{SetHashCode:int}" 

and Input parameter:

[Parameter] public int SetHashCode { get; set; } 

and e.g. in OnInitialized you can extract the value from StateContainer like:

protected override void OnInitialized() { var data = (ComplexObject) _stateContainer.ObjectTunnel[SetHashCode]; } 

after that you should also remove the object from the ObjectTunnel. This is basically the whole flow.


Optimizations:

  • I have created a few extension methods to optimize the flow

StateContainerExtensions.cs

public static class StateContainerExtensions { public static int AddRoutingObjectParameter(this StateContainer stateContainer, object value) { stateContainer.ObjectTunnel[value.GetHashCode()] = value; return value.GetHashCode(); } public static T GetRoutingObjectParameter<T>(this StateContainer stateContainer, int hashCode) { return (T) stateContainer.ObjectTunnel.PopValue(hashCode); } } 

and DictionaryExtensions.cs

public static class DictionaryExtensions { public static TValue PopValue<TKey, TValue>(this Dictionary<TKey, TValue> dictionary, TKey keyName) where TKey : notnull { var value = dictionary[keyName]; dictionary.Remove(keyName); return value; } } 

With those extension methods you can instead

_stateContainer.ObjectTunnel.Add(data.GetHashCode(), data) 

use just:

_stateContainer.AddRoutingObjectParameter(data); 

and instead:

var data = (ComplexObject) _stateContainer.ObjectTunnel[SetHashCode]; _stateContainer.ObjectTunnel.Remove(SetHashCode); 

use:

var data = _stateContainer.GetRoutingObjectParameter<ComplexObject>(SetHashCode); 
Sign up to request clarification or add additional context in comments.

4 Comments

You sir is da real MVP, this solution is an absolute magnificence.
I think StateContainer must be Scoped instead of the Singleton. I tried Scoped and it works for me. Singleton may cause memory overflow
@RamilAliyev007 Yes and No. The type of Blazor (Server vs WASM) matters. Because in WASM Singleton=Scoped. In case of Blazor server making it scoped is the right way to do so the state container is used per user/circuit and not across all users. Thank you for the heads up.
This is actually a very elegant solution. At first I was thinking that you'd need a service for all types of objects to need to send to other pages but implementing it like this means you only need one StateContainer and it will support the entire application. I like it.
7

If it's a simple value (int, string) then you could just pass this value as a path- or query param to the other page:

From page:

<ul> <li><a href="/page/a">A</a></li> <li><a href="/page/b">B</a></li> <li><a href="/page/c">C</a></li> </ul> 

to page:

@page "/page/{PathParam}" <h1>Page @this.PathParam</h1> @code { [Parameter] public string PathParam { get; set; } } 

However, if the data is more complex, try using one of the options described in here: https://learn.microsoft.com/en-us/aspnet/core/blazor/state-management?view=aspnetcore-5.0&pivots=webassembly (Server-side storage, Browser storage or In-memory state container service)

1 Comment

Thank you for the help. I used a ID from my object so I can use it on the other page.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.