blazor-401753-common-concepts-customize-and-reuse-components.md
Blazor framework allows you to build and reuse composite components. You can also render parts or entire components dynamically in C#.
This section describes how to create a composite Blazor component.
In Solution Explorer , right-click a folder with components and select Add → New Item. In the Add New Item dialog, select Razor Component , enter the component’s name, and click Add.
Add DevExpress Blazor components to the newly created *.razor file:
Add MyComponent code to a page (for example, Index.razor):
Refer to Microsoft documentation for additional information on how to create ASP.NET Core Razor components.
You can use the following methods to render Blazor components dynamically:
A render fragment is a custom UI element that you can reuse on pages or in component markup. To define a fragment, use either Razor template syntax or the RenderFragment delegate. To insert the fragment into markup, use the @ symbol.
The following code snippet demonstrates the renderTextBox fragment that renders a Text Box component.
@{
RenderFragment<string> renderTextBox = (string model) =>
@<DxTextBox Text="@model"></DxTextBox>;
}
@renderTextBox("MyText")
The following code snippet demonstrates the renderGrid fragment that renders the Grid component.
@{
RenderFragment<DataItem> renderGrid = (model) =>
@<DxGrid @key="@model" Data="@model.Data">
@foreach (var column in model.ColumnNames) {
<DxGridDataColumn FieldName="@column" @key="@column" />
}
</DxGrid>;
}
@renderGrid(dataObject)
Note that you cannot use this approach in code-behind (.cs) files.
You can use the RenderFragment delegate to define render fragments for simple, nested components, and components that include <Template> elements.
The code above uses template syntax to render a Text Box component. You can render the same component dynamically using the RenderFragment delegate. To define a render fragment, call the RenderTreeBuilder‘s methods: OpenComponent, AddAttribute, and CloseComponent.
@renderTextBox()
@code {
private RenderFragment renderTextBox() {
RenderFragment item = b => {
b.OpenComponent<DxTextBox>(0);
b.AddAttribute(1, "Text", "My text");
b.CloseComponent();
};
return item;
}
}
Optionally, you can call the AddComponentReferenceCapture method to capture a reference to the component, for example:
builder.AddComponentReferenceCapture(n++, grid => Grid = (IGrid)grid);
Note
Refer to Manually build a render tree for additional information on how to use RenderTreeBuilder.
You can create render fragments for nested components. For example, you need to build a Form Layout that contains a tabbed group with an item:
<DxFormLayout>
<DxFormLayoutTabPage Caption="My Tab">
<DxFormLayoutItem Caption="DynLayoutItem" ColSpanMd="6">
</DxFormLayoutItem>
</DxFormLayoutTabPage>
</DxFormLayout>
To build this component, define a render fragment that contains <DxFormLayoutTabPage>. Then add the ChildContent attribute that specifies a nested render fragment for <DxFormLayoutItem>. To add the attribute, call the AddAttribute(sequence, “ChildContent”, RenderFragment) method.
<DxFormLayout>
<DxFormLayoutTabPages>
@renderLayoutTabPage()
</DxFormLayoutTabPages>
</DxFormLayout>
@code {
private RenderFragment renderLayoutTabPage() {
RenderFragment item = b => {
b.OpenComponent<DxFormLayoutTabPage>(0);
b.AddAttribute(1, "Caption", "My tab");
b.AddAttribute(2, "ChildContent", (RenderFragment)((tabPageBuilder) => {
tabPageBuilder.OpenComponent<DxFormLayoutItem>(0);
tabPageBuilder.AddAttribute(1, "Caption", "DynLayoutItem");
tabPageBuilder.AddAttribute(2, "ColSpanMd", 6);
tabPageBuilder.CloseComponent();
}));
b.CloseComponent();
};
return item;
}
}
A component can contain a template with another component, for example:
<DxFormLayout>
<DxFormLayoutTabPage Caption="My Tab">
<DxFormLayoutItem Caption="DynLayoutItem" ColSpanMd="6">
<Template>
<DxTextBox @bind-Text="@text"></DxTextBox>
</Template>
</DxFormLayoutItem>
</DxFormLayoutTabPage>
</DxFormLayout>
To build this component, use the following code snippet. To add the <Template> attribute, use the AddAttribute(sequence, “Template”, RenderFragment<Object>delegate) method.
<DxFormLayout>
<DxFormLayoutTabPages>
@renderLayoutTabPage()
</DxFormLayoutTabPages>
</DxFormLayout>
@code {
private RenderFragment renderLayoutTabPage() {
RenderFragment item = b => {
b.OpenComponent<DxFormLayoutTabPage>(0);
b.AddAttribute(1, "Caption", "My tab");
b.AddAttribute(2, "ChildContent", (RenderFragment)((tabPageBuilder) => {
tabPageBuilder.OpenComponent<DxFormLayoutItem>(0);
tabPageBuilder.AddAttribute(1, "Caption", "DynLayoutItem");
tabPageBuilder.AddAttribute(2, "ColSpanMd", 6);
tabPageBuilder.AddAttribute(3, "Template", (RenderFragment<Object>)((context) => ((itemTemplate) => {
itemTemplate.OpenComponent<DxTextBox>(0);
itemTemplate.AddAttribute(1, "Text", text);
itemTemplate.CloseComponent();
})));
tabPageBuilder.CloseComponent();
}));
b.CloseComponent();
};
return item;
}
}
To create and reuse a modified version of an existing DevExpress Blazor component, create a ComponentBase descendant and override the BuildRenderTree method to generate the component’s content.
For example, you need to add multiple Grid components to an application, and some of them (Group 1) should have the same settings. You can end up with repeated code like demonstrated in the following example:
Group 1
<DxGrid PageSize="5" ShowFilterRow="false" PagerVisible="false" ShowGroupPanel="true" ...>
<DxGrid PageSize="5" ShowFilterRow="false" PagerVisible="false" ShowGroupPanel="true" ...>
<DxGrid PageSize="5" ShowFilterRow="false" PagerVisible="false" ShowGroupPanel="true" ...>
...
Group 2
<DxGrid PageSize="15" ShowFilterRow="false" ShowGroupPanel="false" SelectionMode="GridSelectionMode.Single" ...>
...
You can turn repeated code into a single composite parameter (for example, Settings). This parameter can accept a dictionary with grid settings.
Create a ComponentBase descendant (for example, MyGrid).
Add the Data, ChildContent (for columns), and Settings parameters to the class.
Override the BuildRenderTree method to define the MyGrid<T> component’s markup. This method accepts a RenderTreeBuilder object. Use its methods to add <DxGrid> to the markup and specify the component’s attributes.
Add the MyGrid component to a page.
View Example: How to use a dictionary to configure the Grid stateView Example: Set predefined settings for the specific component