【问题标题】:Dynamically create CascadingValue in custom base component class在自定义基组件类中动态创建 CascadingValue
【发布时间】:2020-12-23 20:34:36
【问题描述】:

我正在使用一个自定义基组件类,每个自定义页面都从中继承。

我没有任何剃须刀代码,因为它不会在我的基本组件类中进行模板化 - 它只应该包含一些基本逻辑和初始化内容。

现在我想包装一个级联值,因为在任何将嵌套在任何子级别中的组件/页面上都应该可以访问我的基类的属性值。我该怎么做,我试图在基本组件上伪造一些 childContent 但我没有工作

public class BaseComponent : ComponentBase
{
    [Parameter] public RenderFragement ChildContent {get;set;}     
    protected override void OnInitialized()
    {
        ChildContent = b =>
        {
            b.OpenComponent<CascadingValue<IBvdDataComponent>>(0);
            b.AddAttribute(1, "Name", "DataComponent");
            b.AddAttribute(2, "Value", this);
            b.CloseComponent();
         };

    }
}


   My page component:

@page "/anypage"
@inherits BaseComponent

    <div>
        <MyNestedComponent />
    </div>

在 MyNestedComponent 我想做的事情:

[CascadingParameter]
public BaseComponent BaseComponent { get; set; }

这样做的正确方法是什么。

【问题讨论】:

  • 我不认为你会用这种方法成功 - github.com/dotnet/aspnetcore/issues/22411
  • 不完全是我正在寻找的,因为他们大多使用剃刀语法来获取围绕其基本组件的 CascadingValue。我尝试动态注入它。我尝试按照 chrissinty link 的指示进行操作。但我没有成功。 buildRenderTree 方法永远不会被调用 - 我不知道为什么
  • 因为当你从一个组件下降时,它会覆盖 BuildRenderTree。
  • 好吧 - 这是有道理的。我不知道 BuildRenderTree 被完全覆盖
  • 如果您查看 obj 文件夹,您可以找到为您的 razor 文件生成的 CS 文件。

标签: blazor blazor-server-side


【解决方案1】:

如果你乐于使用一点反射,这是可能的。

public class MyBase : ComponentBase
{
    string someValue = "test";
    public MyBase()
    {
        var rf = typeof(ComponentBase).GetField("_renderFragment", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        var pqr= typeof(ComponentBase).GetField("_hasPendingQueuedRender", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        var nr= typeof(ComponentBase).GetField("_hasNeverRendered", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
        rf.SetValue(this, (RenderFragment)(builder =>
        {
            pqr.SetValue(this, false);
            nr.SetValue(this, false);
            builder.OpenComponent<CascadingValue<string>>(1);
            builder.AddAttribute(2, "Value", someValue);
            builder.AddAttribute(3, "ChildContent", (RenderFragment)( builder2 => BuildRenderTree(builder2)));
            builder.CloseComponent();
        }));
    }
}

这将自动为所有子组件包含“someValue”的 CascadingValue。

如果你不想使用反射,你可以创建自己的基础组件来实现ComponentBase 所做的一切,然后以类似的方式修改构造函数,但直接引用字段而不是使用反射。

【讨论】:

  • 是的 - 这似乎是我要考虑的方式。谢谢
【解决方案2】:

我有类似的情况,我需要在基本组件类中创建一个CascadingValue,因为我想要一个对父级的引用并允许自定义 HTML 标记,我能弄清楚如何实现这一点的唯一方法是手动构建组件树,但我没有在 Base 构造函数中使用 Reflection,而是使用了 BuildRenderTree(RenderTreeBuilder builder) 方法。

public class Panel : ComponentBase
{
  [CascadingParameter]
  public Panel ParentPanel { get; set; }

  [Parameter]
  public RenderFragment ChildContent { get; set; }

  [Parameter]
  public string Tag { get; set; } = "div";
      
  protected override void BuildRenderTree(RenderTreeBuilder builder)
  {
     base.BuildRenderTree(builder);

     // Add the panel element
     builder.OpenElement(0, Tag);

     // Add the CascadingValue component
     builder.OpenComponent<CascadingValue<Panel>>(1);
     builder.AddAttribute(2, "Value", this);

     // Need to add the ChildContent attribute first then add the actual ChildContent component
     // using a callback
     builder.AddAttribute(3, "ChildContent", (RenderFragment)((builder2) => {
        builder2.AddContent(4, ChildContent);
     }));

     builder.CloseComponent();  // Close the CascadingValue
     builder.CloseElement();    // Close the Tag element
  }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-10
    相关资源
    最近更新 更多