Blazor server component Render, RenderFragment, RenderTreeBuilder, CascadingValue / CascadingParameter

First, components

Microsoft's support Blazor of two mature technologies, Razor Templates and SignalR, is the meeting point of the two components. Usually, we derive from ComponentBase type, or .razor file created, it can be called components. Based on these two technologies, the assembly will have two functions, 1, fragments generated html; 2, maintenance component state. Here we look at the components for the most basic functions, generate html fragments.

二、RenderTreeBuilder,RenderFragment

We know that the browser when the HTML document will deal with all the tags are linked to a document tree, no matter where HTML paragraph from, there will always be plainly tree arrangements. In other words, if there are lines, we can rely on this tree all the labels to string together, but also in Blazor components such a line, this line is RenderTreeBuilder, take this line of people just Blazor framework .

Note this: The following code involved, unless otherwise specified, refer written in .cs file, inherited Microsoft.AspNetCore.Components.ComponentBase component class.

See below this line with the code. Blazor create a new application project, add a class c #, MyCompinheritance Microsoft.AspNetCore.Components.ComponentBase, then override it, find the following method:

 protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            base.BuildRenderTree(builder);//加断点
        }

Add a breakpoint, add a line item in the Pages \ Index.razor years. <MyComp />
If you do not want to code execution twice, then change it in Pages_Host.cshtml in rendermode

 @(await Html.RenderComponentAsync<App>(RenderMode.Server))

F5 run, although there is no output, but hit a breakpoint, RenderTreeBuilder this line really strung our components.
Now let's see what you can do RenderTreeBuilder.

  protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.AddMarkupContent(0, "<span> BuildRenderTree  使用 AddMarkupContent 输出 Html 。</span>");
           // base.BuildRenderTree(builder);
        }

Run up again, we found more than we increase the span on the page. That's HTML output, relied on various methods of calling RenderTreeBuilder plus. The basic principle component that is the case, a RenderTreeBuilder enter BuildRenderTree method different components, through add .. open .. methods on the part of our RenderTreeBuilder want to export, mounted inside the method to the builder, the final output to the browser.

Next, we examine the BuildRenderTreemethods used to describe the commission, we found that this is a Action<RenderTreeBuilder>.

We mentioned in the title RenderFragment, look at its definition.

public delegate void RenderFragment(RenderTreeBuilder builder);//还是一个 Action<RenderTreeBuilder>,或者说,BuildRenderTree 就是一个RenderFragment

We found and in front of BuildRenderTreeexactly the same on the signature, since blazor use RenderTreeBuilder to call BuildRenderTree method, then RenderFragment will also be called?

Let us temporarily leave the assembly MyComp, to add some inside Index.razor code

 @code{
     RenderFragment MyRender=(builder) => builder.AddMarkupContent(0, "<span>当前输出来自:Index.razor 组件, MyRender 字段。 </span>");
        
}

After Before we declare MyComp components, plus line calls @MyRender.
Complete Index.razor

@page "/"

<MyComp />

 @MyRender

@code{
     
    RenderFragment MyRender = (builder) => builder.AddMarkupContent(0, "<div>当前输出来自:Index.razor 组件, MyRender 字段。 </div>");

}

Two pieces of information, do so output proved blazor able to identify the template RenderFragment, and automatically call.
Since we (Index.razor) RenderFragment written in assembly template, of course, there are other ways you can not put together a string.

 RenderFragment AnotherRender =@<div>模板写法的RenderFragment</div>;

Plus calls @AnotherRender, running up, three pieces of information.

At this point, we have a rough idea of RenderFragment, it is a function, internal packing our output. We can use the template, @xxxrenderwill expand its output in place, we can in c # environment through the xxxrender(builder)call (such as calls within BuildRenderTree method) form. And because it is itself a delegate function, so we can use that is within the component can also be passed between components of freedom, complete reuse of the content and output logic.
Meanwhile, in order to better fit RenderFragment use, Blazor also provides a plant delegate, RenderFragment, i.e. Func <TValue, RenderFragment> following the general usage

//模板中(Index.razor)
RenderFragment<object> RenderValue =value=> @<div> render value :@value</div>;

Call @RenderValue (123)if the c # code, such as in BuildRenderTree method RenderValue (123)(builder).

In vs * .razor at compile time .g.cs generate a corresponding code position at obj / debug / netcoreapp3.0 / razor, you can be more open look.

Three, RenderFragment some usage

1, html, we can add in a pair of label content, for example <div>123</div>, the default component does not support this type of operation, then we need to RenderFragment content within the package label.

Let's go back MyComp component class, add an attribute

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

Index.razor

<MyComp><div> 组件标记内部</div></MyComp>

At this time, direct running, an internal component does not output information, it needs to be performed in the BuildRenderTree

  protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
          ChildContent?.Invoke(builder);
          
            base.BuildRenderTree(builder);
        }

Segment within the component tag is packed into the ChildContent, has become a separate segment, so we need to explicitly call it.
ChildContent is a special name

2, a plurality of components on RenderFragment

   [Parameter] public RenderFragment Fragment1 { get; set; }
        [Parameter] public RenderFragment Fragment2 { get; set; }

At this point calls need to adjust, or framework does not know the contents of the packaging segment in which property into

 <MyComp>
        <Fragment1>

            <div> Fragment1 </div>
        </Fragment1>
        <Fragment1>
            <div> Fragment1.1  </div>

        </Fragment1>
        <Fragment2>
            <div> Fragment2  </div>

        </Fragment2>
  
    </MyComp>

Here deliberately repeated the process Fragment1, you can see the results.

3, RenderFragment with parameter
code:

[Parameter] public RenderFragment<MyComp> ChildContent { get; set; }

Calling and parameter passing

  <MyComp Context="self" > //<ChildContent>
       @self.GetType()
      
    </MyComp>  //</ChildContent>

4, component internally labeled declared open, in addition to the parameters used RenderFragment property, the other syntax razor basic support, also comprising a further component.
such as

  <MyComp>
         <CompA />
          <CompB> ...... </CompB>
</MyComp>

or

  <MyComp>
       <Fragment1>
         <CompA />
      </Fragment1>

          <Fragment2>
          <CompB> ...... </CompB>
          </Fragment2>
</MyComp>

Although it seems, declarative markup code is very similar, but has a substantial difference.
When we use a declaration tag attribute parameters, we are generating RenderFragment, and then assign it to the corresponding property.
When we use a component tag statement, we are constructing a component instance, and then call it, the assembly is inserted into a position output components reside.
Parameters property (RenderFragment) belongs to a component, the component is an attribute of the relationship with each other is clear type "=" membership.
Other components of the internal components of the mark many times just to reuse some of the output fragment, if not some processing by the code, is not clearly know the relationship between the components.

四、CascadingValue/CascadingParameter

After assembly increased, data sharing and transfer relationships between components and between components will become very cumbersome when a small number, can also be used to manually specify @ref, clearly not a good method @ref after multiplied. CascadingValue components and the corresponding properties [CascadingParameter] is to solve this problem occurs.

All components within the CascadingValue comprises a child, as long as the appended [CascadingParameter] on the characteristic properties of the component, and the value of the content is compatible, this property will be assigned.

Such as receiving component to define attributes CascadingValue

        [CascadingParameter] public  int Value { get; set; }
        [CascadingParameter] public string SValue { get; set; }

//修改下输出
    protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.AddMarkupContent(0, $"<div>CascadingValue: {Value},{SValue} </div>");// 一个int,一个string
            ChildContent?.Invoke(this)(builder);//加载下级组件
            base.BuildRenderTree(builder);
        }

In the razor page

 <CascadingValue Value="123"> //int
      <MyComp>
                         <MyComp></MyComp>
                     </MyComp>
</CascadingValue >

After the execution we will find that the two components are captured int value 123.
Now add a CascadingValue

 <CascadingValue Value="123"> //int
<CascadingValue Value="@("aaaa")"> //string
      <MyComp>
                         <MyComp></MyComp>
                     </MyComp>
</CascadingValue >
</CascadingValue >

Belong to two different types of CascadingValue two values, it was captured to two properties of each component, convenient and powerful HTML itself does not produce any output, so very wide usage scenarios. Forms assembly is such official means CascadingValue / Parameter complete model is provided, another example, there is no default handling assembly Sons, includes an interface relationship, then you can simply define a [CascadingParameter] public ComponentBase Parent{get;set;}dedicated parent receiving component, the processing similar to Table / Columns like the component relationship.

V. Summary

Components are for their own BuildRenderTree method (RenderFragment) services, a variety of methods on the properties of the components, are designed to prepare the environment to RenderFragment do, so assembly is essentially a wrapper class RenderFragment. Components of the system is called by a RenderTreeBuilder each component in turn, collect the output content, and ultimately to the completion of the internal system output.
1, .Razor file will be compiled into a component class (obj / Debug / netcore3.0 / Razor / ...)
2, components of the system create RenderTreeBuilder, take it to a component instance
3, component instance using RenderTreeBuilder, calls itself BuildRenderTree .
4. Wait for the state change of the component, again output.

 

Original connection: https://www.cnblogs.com/cerl/p/11834510.html

First, components

Microsoft's support Blazor of two mature technologies, Razor Templates and SignalR, is the meeting point of the two components. Usually, we derive from ComponentBase type, or .razor file created, it can be called components. Based on these two technologies, the assembly will have two functions, 1, fragments generated html; 2, maintenance component state. Here we look at the components for the most basic functions, generate html fragments.

二、RenderTreeBuilder,RenderFragment

We know that the browser when the HTML document will deal with all the tags are linked to a document tree, no matter where HTML paragraph from, there will always be plainly tree arrangements. In other words, if there are lines, we can rely on this tree all the labels to string together, but also in Blazor components such a line, this line is RenderTreeBuilder, take this line of people just Blazor framework .

Note this: The following code involved, unless otherwise specified, refer written in .cs file, inherited Microsoft.AspNetCore.Components.ComponentBase component class.

See below this line with the code. Blazor create a new application project, add a class c #, MyCompinheritance Microsoft.AspNetCore.Components.ComponentBase, then override it, find the following method:

 protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            base.BuildRenderTree(builder);//加断点
        }

Add a breakpoint, add a line item in the Pages \ Index.razor years. <MyComp />
If you do not want to code execution twice, then change it in Pages_Host.cshtml in rendermode

 @(await Html.RenderComponentAsync<App>(RenderMode.Server))

F5 run, although there is no output, but hit a breakpoint, RenderTreeBuilder this line really strung our components.
Now let's see what you can do RenderTreeBuilder.

  protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.AddMarkupContent(0, "<span> BuildRenderTree  使用 AddMarkupContent 输出 Html 。</span>");
           // base.BuildRenderTree(builder);
        }

Run up again, we found more than we increase the span on the page. That's HTML output, relied on various methods of calling RenderTreeBuilder plus. The basic principle component that is the case, a RenderTreeBuilder enter BuildRenderTree method different components, through add .. open .. methods on the part of our RenderTreeBuilder want to export, mounted inside the method to the builder, the final output to the browser.

Next, we examine the BuildRenderTreemethods used to describe the commission, we found that this is a Action<RenderTreeBuilder>.

We mentioned in the title RenderFragment, look at its definition.

public delegate void RenderFragment(RenderTreeBuilder builder);//还是一个 Action<RenderTreeBuilder>,或者说,BuildRenderTree 就是一个RenderFragment

We found and in front of BuildRenderTreeexactly the same on the signature, since blazor use RenderTreeBuilder to call BuildRenderTree method, then RenderFragment will also be called?

Let us temporarily leave the assembly MyComp, to add some inside Index.razor code

 @code{
     RenderFragment MyRender=(builder) => builder.AddMarkupContent(0, "<span>当前输出来自:Index.razor 组件, MyRender 字段。 </span>");
        
}

After Before we declare MyComp components, plus line calls @MyRender.
Complete Index.razor

@page "/"

<MyComp />

 @MyRender

@code{
     
    RenderFragment MyRender = (builder) => builder.AddMarkupContent(0, "<div>当前输出来自:Index.razor 组件, MyRender 字段。 </div>");

}

Two pieces of information, do so output proved blazor able to identify the template RenderFragment, and automatically call.
Since we (Index.razor) RenderFragment written in assembly template, of course, there are other ways you can not put together a string.

 RenderFragment AnotherRender =@<div>模板写法的RenderFragment</div>;

Plus calls @AnotherRender, running up, three pieces of information.

At this point, we have a rough idea of RenderFragment, it is a function, internal packing our output. We can use the template, @xxxrenderwill expand its output in place, we can in c # environment through the xxxrender(builder)call (such as calls within BuildRenderTree method) form. And because it is itself a delegate function, so we can use that is within the component can also be passed between components of freedom, complete reuse of the content and output logic.
Meanwhile, in order to better fit RenderFragment use, Blazor also provides a plant delegate, RenderFragment, i.e. Func <TValue, RenderFragment> following the general usage

//模板中(Index.razor)
RenderFragment<object> RenderValue =value=> @<div> render value :@value</div>;

Call @RenderValue (123)if the c # code, such as in BuildRenderTree method RenderValue (123)(builder).

In vs * .razor at compile time .g.cs generate a corresponding code position at obj / debug / netcoreapp3.0 / razor, you can be more open look.

Three, RenderFragment some usage

1, html, we can add in a pair of label content, for example <div>123</div>, the default component does not support this type of operation, then we need to RenderFragment content within the package label.

Let's go back MyComp component class, add an attribute

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

Index.razor

<MyComp><div> 组件标记内部</div></MyComp>

At this time, direct running, an internal component does not output information, it needs to be performed in the BuildRenderTree

  protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
          ChildContent?.Invoke(builder);
          
            base.BuildRenderTree(builder);
        }

Segment within the component tag is packed into the ChildContent, has become a separate segment, so we need to explicitly call it.
ChildContent is a special name

2, a plurality of components on RenderFragment

   [Parameter] public RenderFragment Fragment1 { get; set; }
        [Parameter] public RenderFragment Fragment2 { get; set; }

At this point calls need to adjust, or framework does not know the contents of the packaging segment in which property into

 <MyComp>
        <Fragment1>

            <div> Fragment1 </div>
        </Fragment1>
        <Fragment1>
            <div> Fragment1.1  </div>

        </Fragment1>
        <Fragment2>
            <div> Fragment2  </div>

        </Fragment2>
  
    </MyComp>

Here deliberately repeated the process Fragment1, you can see the results.

3, RenderFragment with parameter
code:

[Parameter] public RenderFragment<MyComp> ChildContent { get; set; }

Calling and parameter passing

  <MyComp Context="self" > //<ChildContent>
       @self.GetType()
      
    </MyComp>  //</ChildContent>

4, component internally labeled declared open, in addition to the parameters used RenderFragment property, the other syntax razor basic support, also comprising a further component.
such as

  <MyComp>
         <CompA />
          <CompB> ...... </CompB>
</MyComp>

or

  <MyComp>
       <Fragment1>
         <CompA />
      </Fragment1>

          <Fragment2>
          <CompB> ...... </CompB>
          </Fragment2>
</MyComp>

Although it seems, declarative markup code is very similar, but has a substantial difference.
When we use a declaration tag attribute parameters, we are generating RenderFragment, and then assign it to the corresponding property.
When we use a component tag statement, we are constructing a component instance, and then call it, the assembly is inserted into a position output components reside.
Parameters property (RenderFragment) belongs to a component, the component is an attribute of the relationship with each other is clear type "=" membership.
Other components of the internal components of the mark many times just to reuse some of the output fragment, if not some processing by the code, is not clearly know the relationship between the components.

四、CascadingValue/CascadingParameter

After assembly increased, data sharing and transfer relationships between components and between components will become very cumbersome when a small number, can also be used to manually specify @ref, clearly not a good method @ref after multiplied. CascadingValue components and the corresponding properties [CascadingParameter] is to solve this problem occurs.

All components within the CascadingValue comprises a child, as long as the appended [CascadingParameter] on the characteristic properties of the component, and the value of the content is compatible, this property will be assigned.

Such as receiving component to define attributes CascadingValue

        [CascadingParameter] public  int Value { get; set; }
        [CascadingParameter] public string SValue { get; set; }

//修改下输出
    protected override void BuildRenderTree(RenderTreeBuilder builder)
        {
            builder.AddMarkupContent(0, $"<div>CascadingValue: {Value},{SValue} </div>");// 一个int,一个string
            ChildContent?.Invoke(this)(builder);//加载下级组件
            base.BuildRenderTree(builder);
        }

In the razor page

 <CascadingValue Value="123"> //int
      <MyComp>
                         <MyComp></MyComp>
                     </MyComp>
</CascadingValue >

After the execution we will find that the two components are captured int value 123.
Now add a CascadingValue

 <CascadingValue Value="123"> //int
<CascadingValue Value="@("aaaa")"> //string
      <MyComp>
                         <MyComp></MyComp>
                     </MyComp>
</CascadingValue >
</CascadingValue >

Belong to two different types of CascadingValue two values, it was captured to two properties of each component, convenient and powerful HTML itself does not produce any output, so very wide usage scenarios. Forms assembly is such official means CascadingValue / Parameter complete model is provided, another example, there is no default handling assembly Sons, includes an interface relationship, then you can simply define a [CascadingParameter] public ComponentBase Parent{get;set;}dedicated parent receiving component, the processing similar to Table / Columns like the component relationship.

V. Summary

Components are for their own BuildRenderTree method (RenderFragment) services, a variety of methods on the properties of the components, are designed to prepare the environment to RenderFragment do, so assembly is essentially a wrapper class RenderFragment. Components of the system is called by a RenderTreeBuilder each component in turn, collect the output content, and ultimately to the completion of the internal system output.
1, .Razor file will be compiled into a component class (obj / Debug / netcore3.0 / Razor / ...)
2, components of the system create RenderTreeBuilder, take it to a component instance
3, component instance using RenderTreeBuilder, calls itself BuildRenderTree .
4. Wait for the state change of the component, again output.

 

Original connection: https://www.cnblogs.com/cerl/p/11834510.html

Guess you like

Origin www.cnblogs.com/bigmango/p/11869160.html