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