I have an IClipboardService I was injecting into components, but as there is only ever one, I decided to try using a CascadingValue instead.
I recreated all this in a minimal test case. Just add these changes to a basic WebAssembly Blazor app:
I created a CascadingClipboard.razor component that looks like this
<CascadingValue Value="_clipboardService">
    @ChildContent
</CascadingValue>
@inject ClipboardService _clipboardService
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }
}
I also created a far simpler test CascadingInt.razor component with an int value
<CascadingValue IsFixed=true Value="_int">
    @ChildContent
</CascadingValue>
@code {
    [Parameter]
    public RenderFragment ChildContent { get; set; }
    public int _int { get; set; } = 123;
}
I wrapped the MainLayout.razor with both:
@inherits LayoutComponentBase
<CascadingClipboard>
    <CascadingInt>
    <div class="page">
        <div class="sidebar">
            <NavMenu />
        </div>
        <main>
            <div class="top-row px-4">
                <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a>
            </div>
            <article class="content px-4">
                @Body
            </article>
        </main>
    </div>
    </CascadingInt>
</CascadingClipboard>
Added receiving CascadingParameters in Index.razor
@page "/"
<PageTitle>Index</PageTitle>
<h1>Hello, world!</h1>
Welcome to your new app.
<SurveyPrompt Title="How is Blazor working for you?" />
@code{
    [CascadingParameter]
    public CascadingClipboard _cascadingClipboard { get; set; }
    [CascadingParameter]
    public int IntValue { get; set; }
    protected override async Task OnParametersSetAsync()
    {
        // BREAKPOINT HERE TO CHECK VALUES
        await base.OnParametersSetAsync();
    }
}
The simple value is always present. The complex object is always null.
I have tried using an explicit assignment instead of injection, but no difference.
Is this simply a limitation of Blazor CascadingValues?
The reason I tried this in the first place, is that my clipboard singleton needed to be initialised from local storage (to happily survive a refresh, or even returning later). Having a Cascading component makes that easy, but leaving the mechanics as a separate injectable service means I can still inject it into non-components (whereas Cascading only works with components). I now have a pattern for the best of both worlds.
I feel like a bit of an idiot, but this may help someone else:
Assignment of a CascadingValue to a CascadingParameter works similar to as casting in C#. If the value types do not match it will be null.
If you look at my example, it had the same typo as in my original app, I was effectively trying to assign a ClipboardService object to a CascadingClipboard parameter.
It does not pay to trust Intellisence all the time :)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With