How to Add Blazor UI Controls to Your Web Application
Blazor is a framework for building rich, interactive client-side web UI using C# instead of JavaScript,sharing server-side and client-side app logic written in .NET. The numerous advantages of Blazor include integration with modern hosting platforms, such as Docker, and building hybrid desktop and mobile apps.
This blog post will guide you on creating a new Blazor Server Application with Visual Studio 2022 and .NET 6 framework. After configuring the primary application, you will learn how to create and use Blazor Components in a Blazor application, then add and work with third-party Blazor controls by installing the appropriate NuGet packages.
We will be covering working with Blazor WebAssembly Application in a separate blog.
So, let's get started with creating a Blazor Server Application.
Creating a Blazor Application
The steps described in this section will require Visual Studio 2022, as we will be creating the application using .NET 6 framework. So, ensure you are working with Visual Studio 2022 to follow the steps smoothly.
1. Open Visual Studio and select Create a new project. Type 'Blazor' in the search box to minimize the displayed project templates. As depicted in the screenshot below, the Blazor search lists the Blazor application templates, including Blazor Server App and Blazor WebAssembly App for C# language. We will be choosing the Blazor Server App variant to create the Blazor application:
2. The project creation is followed by project configuration providing the basic details like project name and location. In the final step of project configuration, the below screen is displayed to choose the desired .NET framework. Here, we choose .NET 6 framework to create the application, keeping all the other options to default. You may alter the same based on your application requirements:
3. Once the project is created and configured, it by default contains two Blazor components named Counterand FetchData, providing the basic functionality of a counter and displaying the fetched data as a table, respectively. The GIF below demonstrates these components after the application is executed:
The section will help you understand Blazor Components and how to create and use them.
Creating and Adding a Blazor Component
A Blazor component is a self-contained part of UI typically defined in a .razor file using Razor syntax. It defines UI event handlers, binds to input data, and maintains its state and rendering logic. Blazor supports UI encapsulation through components.
The steps ahead will help you understand how to create and consume a Blazor component, assuming that a Blazor application has already been created and configured using the steps defined above.
Step 1: Create the EmployeeCard Component
Let’s create a Blazor component to display details about the employees of an organization. To add a component to the project, right-click on the Pages folder and choose Add → Razor Component. In the Add New Item dialog, provide the name EmployeeCard and click Add as depicted in the image below:
The EmployeeCard component generates a code file with the following code by default.
The generated code has two parts. The upper part of the Blazor component represents the HTML template. A single <div> tag with the component's name represents the template in this case. In the lower part of the Blazor component, we have a @code directive, which wraps the C# code for our Blazor component.
To complete the creation of the EmployeeCard component, let's define the component's HTML template to display the Employee details in an organized manner. The Blazor Server App includes Bootstrap by default, so we will use the Bootstrap card and other HTML tags, i.e., img, H5, H6, etc., to define the component. The markup below defines the EmployeeCard component template:
<div class="card m-2">
<div class="card-body">
<div class="card-text text-center">
<img class="card-img-top" src="@ThumbnailUrl" alt="Card image cap">
<p></p>
<h5>@Name</h5>
</div>
<div>
<h6 class="card-text"><b>Name</b> : <small>John Maer</small></h6>
<h6 class="card-text"><b>Title</b>: <small>Assistant Manager</small> </h6>
<h6 class="card-text"><b>HireDate</b>: <small>3/24/2015</small></h6>
</div>
</div>
</div>
In the above code, the hard-coded values have been assigned to the Blazor component, making it static. However, once defined, the components can be reused multiple times within the same or in multiple applications. Hence, the values must be passed dynamically. We will discuss how to accomplish the same ahead.
Step 2: Define Parameters to Reuse the Blazor Component
Parameters are defined as variables using the C# code in the @code section of the template. They are passed to the HTML elements using the @ symbol as depicted in the code below. These parameters are placeholders for the actual values passed when consuming the component and binding it to data.
@code {
[Parameter]
public string Name { get; set; }
[Parameter]
public string Title { get; set; }
[Parameter]
public string ThumbnailUrl { get; set; }
[Parameter]
public DateTime HireDate { get; set; }
}
Finally, the complete EmployeeCard component would appear as described in the image below:
Step 3: Fetch and Display Employee Details
The template is now ready to display the employee details. We can either add the component to a new razor component or add the route directives to the component itself to consume the EmpoyeeCard component. In this case, we will add a new Razor component by right-clicking on the Pages folder and choosing Add → Razor Component. Name the new component to be EmployeeCardDemo and add the route attribute to navigate to this page and view the EmployeeCard component in action.
We can add a Blazor component within another component, using an HTML tag with the component's name. In our case, <EmployeeCard></EmployeeCard> can be used to place our Blazor component within the EmployeeCardDemo Blazor Component.
Next, we have not hard-coded any values in the component template. Instead, we have used parameters as placeholders for actual values; hence using the template will generate an empty component on the page. When using the component to display the employee details, we must assign values to the parameters. To accomplish the same, we will be fetching data from an XML file to create a list of employee details. We will then create a component for each employee and assign the employee details from the list to display each employee's details.
The code below showcases adding the route attributes to the new razor component (EmployeeCardDemo.razor), fetching the XML data to create an employee details list, and creating multiple components for displaying details of each employee:
@page "/employeecarddemo"
<div class="container">
<div class="row">
@foreach (var employee in employeeList)
{
<div class="col-lg-4 mb-2">
<EmployeeCard ThumbnailUrl=@employee.ThumbnailUrl Name=@employee.Name Title=@employee.Title HireDate=@employee.HireDate></EmployeeCard>
</div>
}
</div>
</div>
@code {
private List<Employee> employeeList;
protected override async Task OnInitializedAsync()
{
XmlRepository repository = new XmlRepository();
employeeList = repository.GetEmployees();
}
}
The code snippet below depicts the implementation of XmlRepository class used to fetch data from XML files:
public class XmlRepository
{
private static List<Employee> _employeeList = new List<Employee>();
private static List<Department> _departmentList = new List<Department>();
public XmlRepository()
{
var assembly = typeof(XmlRepository).GetTypeInfo().Assembly;
//TODO: add culture
var stream = assembly.GetManifestResourceStream("BlazorDemo.Data.employees.xml");
using (var reader = new System.IO.StreamReader(stream))
{
var serializer = new XmlSerializer(typeof(List<Employee>));
_employeeList = (List<Employee>)serializer.Deserialize(reader);
}
var dstream = assembly.GetManifestResourceStream("BlazorDemo.Data.departments.xml");
using (var reader = new System.IO.StreamReader(dstream))
{
var serializer = new XmlSerializer(typeof(List<Department>));
_departmentList = (List<Department>)serializer.Deserialize(reader);
}
}
public List<Employee> GetEmployees()
{
return _employeeList;
}
public List<Department> GetDepartments()
{
return _departmentList;
}
public Department GetDepartment(int index)
{
int realIndex = index - 1;
if (_departmentList.Count > 0 && _departmentList.Count > realIndex)
return _departmentList[realIndex];
else
return null;
}
}
public class Employee
{
public string Name { get; set; }
public string Title { get; set; }
public DateTime HireDate { get; set; }
public double Status { get; set; }
public string ThumbnailImage { get; set; }
public string ThumbnailUrl
{
get
{
return "Employees/" + ThumbnailImage;
}
}
public int DepartmentId { get; set; }
public bool FullTime { get; set; }
}
public class Department
{
public int Id { get; set; }
public string Name { get; set; }
}
Finally let's add the razor component route to NavMenu.razor (Shared → NavMenu.razor) file:
<div class="nav-item px-3">
<NavLink class="nav-link" href="employeecarddemo">
<span class="oi oi-list-rich" aria-hidden="true"></span> Employee Card Demo
</NavLink>
</div>
Step 4: Execute the Application to Observe the Results
Execute the application and navigate to Employee Card Demo to observe the results as depicted in the image below:
Please note that the images used in the above demo are placed in a folder in the project, and their path has been specified in the XML file to fetch the image from the location.
This completes the creation and consumption of a Blazor Component from scratch. Next, we will move on to understand how to consume third-party Blazor controls, considering ComponentOne Blazor Edition controls.
Adding Blazor Controls from NuGet
After understanding how to create and consume Blazor Components from scratch, we will now see how we can work with advanced Blazor controls provided by third-party vendors, i.e., pre-defined Blazor components, which might be required in case we want to create a feature rich desktop application having complex requirements.
We need to have these controls available in the project to work with the third-party controls. This can be accomplished by accessing the NuGet Package Manager for an application via the Tools option in the Menu Bar. From the NuGet Package Manager menu, choose Manage NuGet Packages for Solution, which opens the Manage Packages window as depicted in the screenshot below. It would help if you typed in the package name in the Search panel found under the Browse tab to load the specific packages. Selecting the appropriate package in the left panel, you can install it in the project using the Install option available in the right panel of the window.
In this blog, we will be working with ComponentOne Blazor controls. Compared to the EmployeeCard component used to display the employee details, we will showcase FlexGrid control from the ComponentOne Blazor Edition to display the employee details in a tabular format instead of a card format.
The screenshot below depicts the installation of C1.Blazor.Grid Nuget package:
After you have installed the Nuget package, it starts appearing under the Dependencies → Packages node of the solution explorer window, and all the API members provided by the package become available to be consumed when creating components.
Working with ComponentOne FlexGrid
This section briefly describes how to work with the FlexGrid control in a Blazor application. For details, you may refer to FlexGrid Quickstart.
We will start by registering the client-side sources required by Blazor FlexGrid control, which would help us to work with FlexGrid control. Add the following references to Pages → _Layout.cshtml file under the <head> tag:
<link rel="stylesheet" href="~/_content/C1.Blazor.Core/styles.css" />
<link rel="stylesheet" href="~/_content/C1.Blazor.Grid/styles.css" />
<link rel="stylesheet" href="~/_content/C1.Blazor.ListView/styles.css" />
<link rel="stylesheet" href="~/_content/C1.Blazor.Input/styles.css" />
<link rel="stylesheet" href="~/_content/C1.Blazor.DataPager/styles.css" />
<link rel="stylesheet" href="~/_content/C1.Blazor.Calendar/styles.css" />
<link rel="stylesheet" href="~/_content/C1.Blazor.DateTimeEditors/styles.css" />
<link rel="stylesheet" href="~/_content/C1.Blazor.Chart/styles.css" />
<script src="~/_content/C1.Blazor.Core/scripts.js"></script>
<script src="~/_content/C1.Blazor.Input/scripts.js"></script>
<script src="~/_content/C1.Blazor.Grid/scripts.js"></script>
<script src="~/_content/C1.Blazor.Chart/scripts.js"></script>
<script src="~/_content/C1.Blazor.Calendar/scripts.js"></script>
Next, we add a new Razor component to the project named FlexGridDemo, to showcase the FlexGrid control as depicted below:
Following the same design approach described for the EmployeeCard component, we will add FlexGrid control to the FlexGridDemo razor component. <FlexGrid></FlexGrid> will be used to place FlexGrid component within the FlexGridDemo Blazor Component.
Further, we will bind the FlexGrid to the same datasource used when binding to the EmployeeCard component. The only difference is that we create a C1DataCollection instance and populate it with Employee list data to bind the FlexGrid with C1DataCollection.
The code below showcases adding the route attributes to the new razor component (FlexGridDemo.razor), fetching the XML data to create employee details collection, and creating FlexGrid control for displaying employee details in tabular format. It also binds the SelectionChanged event of FlexGrid to display the total number of rows selected, as the SelectionMode property of FlexGrid has been set to GridSelectionMode.RowRange:
@page "/flexgriddemo"
@using C1.Blazor.Core
@using C1.Blazor.Grid
@using C1.DataCollection
<FlexGrid ItemsSource="employeeDataCollection"
AutoGenerateColumns="false"
GridLinesVisibility="GridLinesVisibility.Horizontal"
DefaultRowHeight="100"
Style="@("max-height:50vh")"
ColumnHeaderStyle="@("background-color:#b71c1c;color:#fff;font-size:16px")"
SelectionStyle="@("background-color:#ef9a9a")"
GroupRowStyle="@("background-color:#e53935;color:#fff")"
AlternatingRowStyle="@("background-color:#ffebee")"
CellStyle="@("align-items:center;padding:8px;")"
IsVirtualizationEnabled="false"
SelectionMode="GridSelectionMode.RowRange"
SelectionChanged="OnSelectionChanged">
<FlexGridColumns>
<GridImageColumn Binding="ThumbnailUrl" Header="Employee Image" ClipPath="circle(50%)" AllowSorting="false" Width="200" />
<GridColumn Binding="Name" Width="200"/>
<GridColumn Binding="Title" WordWrap="true" Width="200"/>
<GridDateTimeColumn Binding="HireDate" Format="d" Mode="GridDateTimeColumnMode.Date" Width="200"/>
</FlexGridColumns>
</FlexGrid>
@code {
private C1DataCollection<Employee> employeeDataCollection;
protected override async Task OnInitializedAsync()
{
XmlRepository repository = new XmlRepository();
var employeeList = repository.GetEmployees();
employeeDataCollection = new C1DataCollection<Employee>(employeeList);
}
public async void OnSelectionChanged(object sender, GridCellRangeEventArgs e)
{
if (e.CellRange != null)
{
int rowsSelected = Math.Abs(e.CellRange.Row2 - e.CellRange.Row) + 1;
await JsRuntime.InvokeVoidAsync("alert", "Number of rows selected:" + rowsSelected.ToString());
}
}
}
Finally let's add the FlexGridDemo razor component route to NavMenu.razor (Shared → NavMenu.razor) file:
<div class="nav-item px-3">
<NavLink class="nav-link" href="flexgriddemo">
<span class="oi oi-list-rich" aria-hidden="true"></span> FlexGrid
</NavLink>
</div>
Execute the application and navigate to FlexGrid to observe the results as depicted in the image below:
The image above demonstrates many benefits of using ComponentOne Blazor Edition controls rather than building components from scratch. You can observe how easy it is to style the grid, display images by simply binding the image path to a column, and many more. You may refer to the following demo, which implements more features than the ones demonstrated above, making the FlexGrid more powerful.
Moreover, one of the interesting benefits of ComponentOne Blazor Edition is the availability of client-side IntelliSense, which saves the user from the hassle of memorizing the API members. The image below demonstrates the use of client-side IntelliSense:
You can download the sample implementing the EmployeeCard and FlexGrid Blazor components from here.
Apart from the basic features showcased in this blog, FlexGrid is feature-rich control, providing many features, including Grouping, Row Details Template, freezing, exporting, etc. You may refer to FlexGrid demos and documentation to explore all the available features.
To explore other controls offered by ComponentOne Blazor Edition, you may refer to Blazor Server Explorer and Blazor Control Explorer demos.