英文:
What are the limitations of Blazor CascadingValue? Complex objects are not being passed
问题
我有一个IClipboardService
,我将其注入到组件中,但由于只会有一个,我决定尝试使用CascadingValue
。
我在一个基本的WebAssembly Blazor应用程序中重新创建了所有这些内容。只需将以下更改添加到其中:
我创建了一个名为CascadingClipboard.razor
的组件,内容如下:
<CascadingValue Value="_clipboardService">
@ChildContent
</CascadingValue>
@inject ClipboardService _clipboardService
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
}
我还创建了一个更简单的测试组件CascadingInt.razor
,它包含一个int
值:
<CascadingValue IsFixed=true Value="_int">
@ChildContent
</CascadingValue>
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
public int _int { get; set; } = 123;
}
然后,我用这两个组件包装了MainLayout.razor
:
@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>
在Index.razor
中添加了接收CascadingParameters
:
@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()
{
// 在此设置断点以检查值
await base.OnParametersSetAsync();
}
}
简单值始终存在,但复杂对象始终为null
。
我尝试过使用显式赋值而不是注入,但没有任何区别。
这是否只是Blazor CascadingValues的一个限制?
更多信息:
我之所以首先尝试这样做,是因为我的剪贴板单例需要从本地存储中初始化(以便在刷新后或稍后返回时保持状态)。使用Cascading组件可以很容易地实现这一点,但将机制保留为一个可注入的服务意味着我仍然可以将其注入到非组件中(而Cascading只能与组件一起使用)。现在我有了一个同时具有两者优点的模式。
英文:
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.
答案1
得分: 3
我觉得有点傻,但这可能对其他人有帮助:
将 CascadingValue
分配给 CascadingParameter
与 C# 中的 as
强制转换类似。如果值的类型不匹配,它将为 null。
如果你看我的示例,它有与我的原始应用程序中一样的拼写错误,实际上我试图将 ClipboardService
对象分配给 CascadingClipboard
参数。
不要总是相信智能感知
英文:
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
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论