Blazor 在自定义基组件类中动态创建CascadingValue

Blazor 在自定义基组件类中动态创建CascadingValue,blazor,blazor-server-side,Blazor,Blazor Server Side,我使用的是一个自定义基组件类,每个自定义页面都是从该类继承的 我没有任何razor代码,因为它不会在我的基本组件类中模板化——它只应该包含一些基本逻辑和初始化内容 现在,我希望围绕一个级联值进行包装,因为在将嵌套在任何子级中的任何组件/页面上,都应该能够访问我的基类的属性值。我如何做到这一点,我试图在基本组件上伪造一些childContent,但我没有成功 public class BaseComponent : ComponentBase { [Parameter] public Re

我使用的是一个自定义基组件类,每个自定义页面都是从该类继承的

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

现在,我希望围绕一个级联值进行包装,因为在将嵌套在任何子级中的任何组件/页面上,都应该能够访问我的基类的属性值。我如何做到这一点,我试图在基本组件上伪造一些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>

正确的方法是什么。

如果您愿意使用一些反射,这是可能的

公共类MyBase:ComponentBase
{
字符串someValue=“test”;
公共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(“_hasneverrended”,System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
rf.SetValue(此(RenderFragment)(生成器=>
{
pqr.设定值(该值为假);
nr.SetValue(该值为假);
OpenComponent(1);
AddAttribute(2,“值”,someValue);
AddAttribute(3,“ChildContent”,(RenderFragment)(builder2=>BuildRenderTree(builder2));
builder.CloseComponent();
}));
}
}
这将自动将“someValue”的CascadingValue包含到所有子组件中


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

我有一个类似的情况,我需要在一个基本组件类中创建一个
CascadingValue
,因为我想要引用父级并允许自定义HTML标记,我唯一能想到的方法是手动构建组件树,但是我没有在基本构造函数中使用
Reflection
,而是使用
BuildRenderTree(RenderTreeBuilder)
方法

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
  }
}
公共类面板:ComponentBase
{
[CascadingParameter]
公共面板ParentPanel{get;set;}
[参数]
公共RenderFragment ChildContent{get;set;}
[参数]
公共字符串标记{get;set;}=“div”;
受保护的覆盖void BuildRenderTree(RenderTreeBuilder)
{
base.BuildRenderTree(builder);
//添加面板元素
builder.OpenElement(0,标记);
//添加CascadingValue组件
OpenComponent(1);
builder.AddAttribute(2,“值”,this);
//需要先添加ChildContent属性,然后添加实际的ChildContent组件
//使用回调
builder.AddAttribute(3,“ChildContent”,(RenderFragment)((builder2)=>{
builder2.AddContent(4,ChildContent);
}));
builder.CloseComponent();//关闭CascadingValue
builder.CloseElement();//关闭标记元素
}
}

我认为这种方法不会成功——这与我想要的不完全一样,因为它们大多使用razor语法来获取基本组件周围的CascadingValue。我尝试动态地注入这个。我试着按照克里斯桑蒂的指示去做。但是我没有成功。buildRenderTree方法从未被调用过-我不知道为什么当你从一个组件下降时它会覆盖buildRenderTree。好吧-这是有意义的。我不知道BuffReDeNeDRead是完全覆盖的。如果你在Obf文件夹中查看,你可以为Ra剃文件找到生成的CS文件。是的,这似乎是我要考虑的方式。非常感谢。
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
  }
}