问题
I'm using a custom base component class from which every custom page inhertits from.
I do not have any razor code, because it won't be templated in my my base component class - it is only supposed to contain some base logics and intialization stuff.
Now i want do wrap around a cascading value, because on any component/page which will be nested within any child level should get access to a property value of my base class. How can i do this, i tried to fake some childContent on the base component but i didnt work
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>
In MyNestedComponent I want to do:
[CascadingParameter]
public BaseComponent BaseComponent { get; set; }
Whats the correct way to do this.
回答1:
If you are happy to use a bit of reflection, it is possible.
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();
}));
}
}
This will automatically include a CascadingValue for "someValue" to all child components.
If you don't want to use reflection, you can create your own base component that implements everything ComponentBase
does, then modify the constructor in a similar way, but directly referencing the fields instead of using reflection.
回答2:
I had a similar situation where I needed to create a CascadingValue
in a Base Component class because I wanted a reference to the Parent and allow custom HTML tags, only way I could figure out how to achieve this was to manually build the component tree, but instead of using Reflection
in the Base constructor I used the BuildRenderTree(RenderTreeBuilder builder)
method.
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
}
}
来源:https://stackoverflow.com/questions/63743386/dynamically-create-cascadingvalue-in-custom-base-component-class