如何在 RenderFragment 中定义模板化组件,其@context 可用 [英] How to define templated component in RenderFragment with its @context available

查看:138
本文介绍了如何在 RenderFragment 中定义模板化组件,其@context 可用的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模板化组件(一个工具提示),它有一个参数并将该参数在上下文中传递给子内容.该参数是 ElementReference 的包装器.这样做的目的是在设置后返回子级参考的工具提示.我想要做的是将该工具提示组件的特定实例存储在多个位置的可重用 RenderFragment 中.但是我收到错误当前上下文中不存在名称上下文".

I have a templated component (a tooltip) that has a parameter and passes that parameter in context to child content. That parameter is a wrapper for ElementReference. The purpose of this is to get back to the tooltip the child's reference, once it is set. What I want to do is to store a particular instance of that tooltip component in a reusable RenderFragment in several places. But I get the error The name 'context' does not exists in the current context.

这是原始问题,但事实证明它过于简单化了.请转到第二个分隔线,样本更像我的情况.

这是一个示例(不是那个工具提示,而是具有完全相同问题的简化代码).
模板化组件RenderFragTempl:

Here is a sample (not that tooltip, but simplified code that has exactly the same problem).
Templated component 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.StackOverflow

<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 被构建为模板化组件.


1
I have a tooltip component that has a child content. Tooltip will be shown whenever the mouse hovers over that child content. But tooltip does not wrap the child content with anything. So if you check out the source, you will only see the child content without any indication of the tooltip. The moment mouse cursor hovers over the child content, the tooltip container is added to the bottom of the page and is position right over that child content. This is quite problematic to achieve in blazor because the tooltip needs to have the reference to the child content. But references are established after parameters are filled. So a special wrapper is used to achieve that and Tooltip is built as a templated component.

所以我使用了 ElementReference 的包装器(MatBlazor 的礼貌):

So the wrapper for ElementReference I use (curtesy of 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;
    }

我简化的TooltipRenderFragTempl(只是重要的部分)

My simplified Tooltip as RenderFragTempl (just the important bits)

@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 用于渲染卡片上的按钮.我想将带有工具提示的图标传递给该卡片.我需要访问工具提示的上下文.

To answer the question - why I am trying to use RenderFragment - imagine I have a collection of cards - let's say 150. The card component accepts as a parameter IList<RenderFragment> for rendering buttons on a card. I want to pass my icon with tooltip to that card. I need to have access to Tooltip's context.

我尝试将上下文重命名为其他名称,但出现相同的错误(除了错误中有新的上下文名称).

I tried renaming context to something else, but I get the same error (except in the error there is new context name).

推荐答案

为什么要定义一个模板化组件并像这样使用它?

Why define a templated component and use it like that ?

但是,这里的代码示例演示了如何在不定义模板化组件的情况下获得相同的所需结果:

However, here's code sample that demonstrates how to get the same required result without defining a templated component:

@test(12)

@code {
    
    private RenderFragment<int> test => (value) => (__builder) =>
    {
        <span id="@(value)">
            @value
        </span>
    };

}

但如果您坚持,这里的代码演示了如何呈现您的组件:

But if you insist, here's the code that demonstrate how to render your component:

@test((10001, 15))

@code 
{
    private RenderFragment<(int, int)> test => (value) => (__builder) =>
    {
        <RenderFragTempl Ref="@value.Item1">
            <IntChildContent>
                <p>@value.Item2</p>
            </IntChildContent>
        </RenderFragTempl>;
   
    };

 }

更新:

以下代码描述了如何使用内部变量上下文渲染模板化组件.您可以随心所欲地改进它.

Update:

The following code describes how to render the templated component with the internal variable context. You can improve on it as you like.

注意:我没有阅读您的更新...我只是按照您对原始问题的要求进行操作,但这次使用上下文.

Note: I did not read your update... I just do what you requested on the original question, but this time using context.

@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 参数的值,并以内部上下文变量的形式传递

Note that when you invoke the RenderFragment delegate you pass it a value which is assigned to the Ref parameter, and is passed in the form the the internal context variable

这篇关于如何在 RenderFragment 中定义模板化组件,其@context 可用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆