Understand Cascading Parameters and Cascading Values in Blazor

In the previous article we discussed arbitrary parameters and attribute splatting. Now it's time to understand one more aspect of passing values to a Blazor component from the external world - Cascading Parameters and Cascading Values. In all the examples discussed so far, we explicitly set a parameter value from the parent component. This means if we want to pass a value to, say, ten components, we must set a parameter of all the ten components. In such cases Cascading Parameters and Cascading Values come  handy. The remainder of this article discusses how.

Open the same Blazor project you created in the previous article. Recollect that we have already created Message component in the project. For the sake of this article, we will create two components - UpperCaseMessage and LowerCaseMessage - to demonstrate our point of discussion

So, add two Razor Components namely UpperCaseMessage.razor and LowerCaseMessage.razor to the project. These are quite simple components that display a specified message in uppercase and lowercase letters respectively. For the sake of clear understanding we will first build them with normal parameters and then convert them to use cascading parameters.

The UpperCaseMessage.razor looks like this:

<h2>@Value.ToUpper()</h2>

@code {

    [Parameter]
    public string Value { get; set; }
}

The LowerCaseMessage.razor looks like this:

<h2>@Value.ToLower()</h2>

@code {

    [Parameter]
    public string Value { get; set; }
}

On the Index.razor parent component you can use them components as follows:

<UpperCaseMessage Value="Hello Universe!">
</UpperCaseMessage>
<LowerCaseMessage Value="Hello Universe!">
</LowerCaseMessage>

And the outcome will be similar to the following figure: 

Now let's change the components to use cascading parameters.

Modify UpperCaseMessage component as shown below:

<h2>@Value.ToUpper()</h2>

@code {

    [CascadingParameter]
    public string Value { get; set; }
}

And LowerCaseMessage component as shown below:

<h2>@Value.ToLower()</h2>

@code {

    [CascadingParameter]
    public string Value { get; set; }
}

As you can see the Value property is now decorated with [CascadingParameter] attribute.

To set the Value cascading parameter from the Index.razor parent component you will use Blazor's CascadingValue component.

<CascadingValue Value="@MessageText">
   <UpperCaseMessage></UpperCaseMessage>
   <LowerCaseMessage></LowerCaseMessage>
</CascadingValue>

@code{
  private string MessageText = "Hello Universe!";
}

The CascadingValue component indicates a value that is passed to all its child components. In this case the value stored in the MessageText string variable (Hello Universe!) is passed to the child components <UpperCaseMessage> and <LowerCaseMessage>.

If you run the application again the results will be identical to the previous example.

Now let's pass one more value to the UpperCaseMessage and LowerCaseMessage components.

<CascadingValue Value="@MessageText">
    <CascadingValue Value="@ShowLength">
        <UpperCaseMessage></UpperCaseMessage>
        <LowerCaseMessage></LowerCaseMessage>
    </CascadingValue>
</CascadingValue>
@code{
    private string MessageText = "Hello Universe!";
    private bool ShowLength = true;
}

As you can see from the above code, we now have two nested <CascadingValue> components. The outer instance passes MessageText and the inner instance passes ShowLength boolean value. We will use this boolean value to display (or not diasplay) the length of the message inside the UpperCaseMessage and LowerCaseMessage components.

So, open UpperCaseMessage.razor and make the following change.

<h2>@Value.ToUpper()</h2>

@if(LengthIndicator)
{
    <h3>(@Value.Length characters)</h3>
}

@code {

    [CascadingParameter]
    public string Value { get; set; }

    [CascadingParameter]
    public bool LengthIndicator { get; set; }
}

As you can see, we added one more [CascadingParameter] property called LengthIndicator. You might be wondering how Blazor maps the cascading values to the cascading parameters. Blazor does so based on data type of the value. In this example, MessageText is a string value and hence it is mapped to the Value string property. Similarly, ShowLength is a boolean value and it is mapped to the LengthIndicator boolean property.

We use the LengthIndicator property in the component markup to output the length of the message.

Modify LowerCase.razor on similar lines.

<h2>@Value.ToLower()</h2>

@if (LengthIndicator)
{
    <h3>(@Value.Length characters)</h3>
}

@code {
    [CascadingParameter]
    public string Value { get; set; }

    [CascadingParameter]
    public bool LengthIndicator { get; set; }
}

Now run the application again. Your output should look like this:

Now let's take this concept one step further. We will pass third cascading value to both the components as shown below:

<CascadingValue Value="@MessageText" Name="MsgText">
    <CascadingValue Value="@ShowLength">
        <CascadingValue Value="@MessageTitle" Name="MsgTitle">
            <UpperCaseMessage></UpperCaseMessage>
            <LowerCaseMessage></LowerCaseMessage>
        </CascadingValue>
    </CascadingValue>
</CascadingValue>
@code{
    private string MessageText = "Hello Universe!";
    private bool ShowLength = true;
    private string MessageTitle = 
"This is a message title from parent.";
}

This time we want to pass three values to both the components. Two of them - MessageText and MessageTitle - are string values whereas ShowLength is boolean. Since there are two string values the Blazor's mapping based on data type might give unexpected results. The safest way is to explicitly assign some Name to the cascading value being passed. Therefore, we named MessageText value as MsgText and MessageTitle as MsgTitle.

Now open UpperCaseMessage component and add this code:

<h2 title="@Title">@Value.ToUpper()</h2>

@if(LengthIndicator)
{
    <h3>(@Value.Length characters)</h3>
}

@code {
    [CascadingParameter(Name = "MsgText")]
    public string Value { get; set; }

    [CascadingParameter]
    public bool LengthIndicator { get; set; }

    [CascadingParameter(Name = "MsgTitle")]
    public string Title { get; set; }
}

Now the Value cascading parameter is explicitly mapped to the MsgText cascading value via the Name property of [CascadingParameter] attribute. And Title cascading property is mapped to MsgTitle cascading value. The Title property is used to set the title attribute of <h2> element.

Make similar changes to the LowerCaseMessage.razor component:

<h2 title="@Title">@Value.ToLower()</h2>

@if (LengthIndicator)
{
    <h3>(@Value.Length characters)</h3>
}

@code {
    [CascadingParameter(Name = "MsgText")]
    public string Value { get; set; }

    [CascadingParameter]
    public bool LengthIndicator { get; set; }

    [CascadingParameter(Name = "MsgTitle")]
    public string Title { get; set; }
}

Running the application after making these changes will produce this output:

Let's conclude this article by observing the state change behavior of cascading values.

We will add a button to our parent component (Index.razor). Clicking on the button will change the values of MessageText, ShowLength, and MessageTitle properties.

<button @onclick="ChangeCascadingValues">
    Change Cascading Parameters
</button>

And the ChangeCascadingValues() event handler method looks like this:

private void ChangeCascadingValues()
{
    MessageText = "Hello Galaxy!";
    MessageTitle = "Message title changed.";
    ShowLength = false;
}

Run the application again and click on the newly added button. You will find that the child components reflect the changed values.

This means Blazor is continuously monitoring the cascading values and updates the child components whenever they change. This constant monitoring can be turned off if you are concerned about the performance. Of course, after disabling that the child components  won't reflect the changed state.

You disable the monitoring using IsFixed property of the <CascadingValue> component. The following code fragment shows how:

<CascadingValue Value="@MessageText" 
Name="MsgText" IsFixed="true">
    <CascadingValue Value="@ShowLength" IsFixed="true">
        <CascadingValue Value="@MessageTitle" 
Name="MsgTitle" IsFixed="true">
            <UpperCaseMessage></UpperCaseMessage>
            <LowerCaseMessage></LowerCaseMessage>
        </CascadingValue>
    </CascadingValue>
</CascadingValue>

We set IsFixed to true for all the three cascading values indicating that the values are fixed (and don't need change monitoring).

After making this change run the application again and click on the button. This time the child components won't reflect any change.

That's it for now! Keep coding!!


Bipin Joshi is an independent software consultant, trainer, author, and meditation teacher. He has been programming, meditating, and teaching for 25+ years. He conducts instructor-led online training courses in ASP.NET family of technologies for individuals and small groups. He is a published author and has authored or co-authored books for Apress and Wrox press. Having embraced the Yoga way of life he also teaches Ajapa Yoga to interested individuals. To know more about him click here.

Get connected : Facebook  Twitter  LinkedIn  YouTube

Posted On : 18 January 2021


Tags : ASP.NET ASP.NET Core .NET Framework C# Visual Studio Components