如何在 RenderFragment 中使用其 @context 可用定义模板化组件
How to define templated component in RenderFragment with its @context available
我有一个模板化组件(工具提示),它有一个参数并将该参数在上下文中传递给子内容。该参数是 ElementReference
的包装器。这样做的目的是在设置后返回到子项参考的工具提示。
我想要做的是将该工具提示组件的特定实例存储在多个位置的可重用 RenderFragment
中。
但是我收到错误 The name 'context' does not exists in the current context
.
这是原来的问题,但被证明过于简单化了。请转到第二条分隔线,样本更像我的情况。
这是一个示例(不是工具提示,而是具有完全相同问题的简化代码)。
模板化组件 RenderFragTempl
:
@inherits ComponentBase
<span id="@(Ref)">
@IntChildContent(Ref)
</span>
@code {
[Parameter] public RenderFragment<int> IntChildContent { get; set; }
[Parameter] public int Ref { get; set; }
}
和 Index.razor
中的调用:
@page "/"
@using BlazorServer.Pages.Whosebug
<RenderFragTempl Ref="10">
<IntChildContent>
<p>@context</p>
</IntChildContent>
</RenderFragTempl>
<br />
@test
@code {
//compiler error CS0103: The name 'context' does not exist in the current context
private readonly RenderFragment test = @<RenderFragTempl Ref="10001">
<IntChildContent>
<p>@context</p>
</IntChildContent>
</RenderFragTempl>;
}
编辑:1
我有一个包含子内容的工具提示组件。只要鼠标悬停在该子内容上,就会显示工具提示。但是工具提示不会用任何东西包裹子内容。因此,如果您查看源代码,您将只能看到子内容,而不会看到任何工具提示。当鼠标光标悬停在子内容上时,工具提示容器将添加到页面底部并位于该子内容的正上方。这在 blazor 中很难实现,因为工具提示需要引用子内容。但是引用是在填入参数后建立的。因此,使用了一个特殊的包装器来实现这一点,并将 Tooltip 构建为模板化组件。
所以我使用 ElementReference
的包装器(由 MatBlazor 提供):
public class TargetForwardRef
{
private ElementReference _current;
public ElementReference Current
{
get => _current;
set
{
Set(value);
//this is just for debugging purpose
Console.WriteLine($"Ref: {value.Id ?? "null"}");
}
}
public void Set(ElementReference value) => _current = value;
}
我将 Tooltip
简化为 RenderFragTempl
(仅重要部分)
@inherits ComponentBase
<span>
@UnboundChildContent(RefBack)
</span>
@code {
[Parameter] public RenderFragment<TargetForwardRef> UnboundChildContent { get; set; }
[Parameter] public TargetForwardRef RefBack { get; set; } = new TargetForwardRef();
}
还有我的index.razor
@page "/"
@*
//this is working, will printout to console `<span>` reference id, you will be
//able to find it once you go to source; I added this here for reference
*@
<RenderFragTempl>
<UnboundChildContent>
<span @ref="@context.Current">Span content</span>
</UnboundChildContent>
</RenderFragTempl>
<br/>
@test
@code {
//compiler error CS0103: The name 'context' does not exist in the current context
private readonly RenderFragment test =
@<RenderFragTempl>
<UnboundChildContent>
<span @ref="@context.Current">Hover to show tooltip</span >
</UnboundChildContent>
</RenderFragTempl>;
}
回答这个问题 - 为什么我要尝试使用 RenderFragment
- 假设我有一组卡片 - 比如说 150。卡片组件接受参数 IList<RenderFragment>
来渲染按钮一张卡。我想将带有工具提示的图标传递给那张卡片。我需要访问工具提示的上下文。
我尝试将上下文重命名为其他名称,但出现相同的错误(除了错误中有新的上下文名称)。
为什么要定义模板化组件并那样使用它?
但是,下面的代码示例演示了如何在不定义模板化组件的情况下获得相同的所需结果:
@test(12)
@code {
private RenderFragment<int> test => (value) => (__builder) =>
{
<span id="@(value)">
@value
</span>
};
}
但如果您坚持,下面是演示如何呈现组件的代码:
@test((10001, 15))
@code
{
private RenderFragment<(int, int)> test => (value) => (__builder) =>
{
<RenderFragTempl Ref="@value.Item1">
<IntChildContent>
<p>@value.Item2</p>
</IntChildContent>
</RenderFragTempl>;
};
}
更新:
以下代码描述了如何渲染带有内部变量上下文的模板化组件。您可以根据自己的喜好对其进行改进。
注意:我没有阅读你的更新...我只是按照你对原始问题的要求做了,但这次使用了上下文。
@test(121)
@code {
private RenderFragment<int> test => (value) => (__builder) =>
{
__builder.OpenComponent<TemplatedComponent>(0);
__builder.AddAttribute(1, "Ref", value);
__builder.AddAttribute(2, "IntChildContent",
(RenderFragment<int>)((context) => (__builder2) =>
{
__builder2.OpenElement(3, "p");
__builder2.AddContent(4, context);
__builder2.CloseElement();
}
));
__builder.CloseComponent();
};
}
请注意,当您调用 RenderFragment 委托时,您向其传递了一个分配给 Ref 参数的值,并以内部上下文变量的形式传递
我在 https://github.com/dotnet/aspnetcore/issues/29671 中问过这个问题,我得到了答案。这不是我想要的,但这似乎是官方的:
private readonly RenderFragment<TargetForwardRef> test => context =>
@<RenderFragTempl>
<UnboundChildContent>
<span @ref="@context.Current">Hover to show tooltip</span >
</UnboundChildContent>
</RenderFragTempl>;
我有一个模板化组件(工具提示),它有一个参数并将该参数在上下文中传递给子内容。该参数是 ElementReference
的包装器。这样做的目的是在设置后返回到子项参考的工具提示。
我想要做的是将该工具提示组件的特定实例存储在多个位置的可重用 RenderFragment
中。
但是我收到错误 The name 'context' does not exists in the current context
.
这是原来的问题,但被证明过于简单化了。请转到第二条分隔线,样本更像我的情况。
这是一个示例(不是工具提示,而是具有完全相同问题的简化代码)。
模板化组件 RenderFragTempl
:
@inherits ComponentBase
<span id="@(Ref)">
@IntChildContent(Ref)
</span>
@code {
[Parameter] public RenderFragment<int> IntChildContent { get; set; }
[Parameter] public int Ref { get; set; }
}
和 Index.razor
中的调用:
@page "/"
@using BlazorServer.Pages.Whosebug
<RenderFragTempl Ref="10">
<IntChildContent>
<p>@context</p>
</IntChildContent>
</RenderFragTempl>
<br />
@test
@code {
//compiler error CS0103: The name 'context' does not exist in the current context
private readonly RenderFragment test = @<RenderFragTempl Ref="10001">
<IntChildContent>
<p>@context</p>
</IntChildContent>
</RenderFragTempl>;
}
编辑:1
我有一个包含子内容的工具提示组件。只要鼠标悬停在该子内容上,就会显示工具提示。但是工具提示不会用任何东西包裹子内容。因此,如果您查看源代码,您将只能看到子内容,而不会看到任何工具提示。当鼠标光标悬停在子内容上时,工具提示容器将添加到页面底部并位于该子内容的正上方。这在 blazor 中很难实现,因为工具提示需要引用子内容。但是引用是在填入参数后建立的。因此,使用了一个特殊的包装器来实现这一点,并将 Tooltip 构建为模板化组件。
所以我使用 ElementReference
的包装器(由 MatBlazor 提供):
public class TargetForwardRef
{
private ElementReference _current;
public ElementReference Current
{
get => _current;
set
{
Set(value);
//this is just for debugging purpose
Console.WriteLine($"Ref: {value.Id ?? "null"}");
}
}
public void Set(ElementReference value) => _current = value;
}
我将 Tooltip
简化为 RenderFragTempl
(仅重要部分)
@inherits ComponentBase
<span>
@UnboundChildContent(RefBack)
</span>
@code {
[Parameter] public RenderFragment<TargetForwardRef> UnboundChildContent { get; set; }
[Parameter] public TargetForwardRef RefBack { get; set; } = new TargetForwardRef();
}
还有我的index.razor
@page "/"
@*
//this is working, will printout to console `<span>` reference id, you will be
//able to find it once you go to source; I added this here for reference
*@
<RenderFragTempl>
<UnboundChildContent>
<span @ref="@context.Current">Span content</span>
</UnboundChildContent>
</RenderFragTempl>
<br/>
@test
@code {
//compiler error CS0103: The name 'context' does not exist in the current context
private readonly RenderFragment test =
@<RenderFragTempl>
<UnboundChildContent>
<span @ref="@context.Current">Hover to show tooltip</span >
</UnboundChildContent>
</RenderFragTempl>;
}
回答这个问题 - 为什么我要尝试使用 RenderFragment
- 假设我有一组卡片 - 比如说 150。卡片组件接受参数 IList<RenderFragment>
来渲染按钮一张卡。我想将带有工具提示的图标传递给那张卡片。我需要访问工具提示的上下文。
我尝试将上下文重命名为其他名称,但出现相同的错误(除了错误中有新的上下文名称)。
为什么要定义模板化组件并那样使用它?
但是,下面的代码示例演示了如何在不定义模板化组件的情况下获得相同的所需结果:
@test(12)
@code {
private RenderFragment<int> test => (value) => (__builder) =>
{
<span id="@(value)">
@value
</span>
};
}
但如果您坚持,下面是演示如何呈现组件的代码:
@test((10001, 15))
@code
{
private RenderFragment<(int, int)> test => (value) => (__builder) =>
{
<RenderFragTempl Ref="@value.Item1">
<IntChildContent>
<p>@value.Item2</p>
</IntChildContent>
</RenderFragTempl>;
};
}
更新:
以下代码描述了如何渲染带有内部变量上下文的模板化组件。您可以根据自己的喜好对其进行改进。
注意:我没有阅读你的更新...我只是按照你对原始问题的要求做了,但这次使用了上下文。
@test(121)
@code {
private RenderFragment<int> test => (value) => (__builder) =>
{
__builder.OpenComponent<TemplatedComponent>(0);
__builder.AddAttribute(1, "Ref", value);
__builder.AddAttribute(2, "IntChildContent",
(RenderFragment<int>)((context) => (__builder2) =>
{
__builder2.OpenElement(3, "p");
__builder2.AddContent(4, context);
__builder2.CloseElement();
}
));
__builder.CloseComponent();
};
}
请注意,当您调用 RenderFragment 委托时,您向其传递了一个分配给 Ref 参数的值,并以内部上下文变量的形式传递
我在 https://github.com/dotnet/aspnetcore/issues/29671 中问过这个问题,我得到了答案。这不是我想要的,但这似乎是官方的:
private readonly RenderFragment<TargetForwardRef> test => context =>
@<RenderFragTempl>
<UnboundChildContent>
<span @ref="@context.Current">Hover to show tooltip</span >
</UnboundChildContent>
</RenderFragTempl>;