4

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?

More info:

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.

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202

1 Answers1

3

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 :)

iCollect.it Ltd
  • 92,391
  • 25
  • 181
  • 202
  • This is because Blazor attempts to do cascading parameter setting by matching type in the absence of a Name attribute. This is why I *always* use a Name with my CascadingValues/Parameters. – Lex Jul 27 '23 at 19:45
  • @Lex Even with the Name supplied (which I also tried), it will not match if the type is wrong, hence my original problem. – iCollect.it Ltd Jul 28 '23 at 07:23
  • 1
    Sorry, I didn't mean to imply that it would work. I thought it would at least throw a runtime error if the types don't match, but after testing I see that it doesn't. That seems dumb, but I suppose they must have some reason not to raise an error. – Lex Jul 28 '23 at 14:56