Separate UI and Code in Blazor
Blazor apps consist of one or more components. Components reside in .razor
files and consist of UI markup and C# code. When you create a new Blazor server
or WebAssembly project it stores component UI and code in a single file.
However, at times this single file approach might not be adequate. Luckily, you
can separate your UI markup and C# code easily. This article shows how.
Single file
Firstly, let's see how the UI markup and C# code is stored under the single
file approach.
Begin by creating a new Blazor server project using Visual Studio. The
following figure shows the newly created project in Solution Explorer.
Then open the Counter.razor component from the Pages folder to reveal this
markup and code:
@page "/counter"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary"
@onclick="IncrementCount">
Click me
</button>
@code {
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
As you can see the component UI markup is placed after @page directive. And
component's C# code is placed inside the @code block.
That means UI markup and C# code are housed in a single file. This
arrangement works well when your components are simple and don't contain huge
chunks of markup and code. Single file approach is also good if you want keep
minimal number of project files. However, if you are developing complex
components you might want to separate UI markup and C# code in separate files.
There are two ways to accomplish that task - Partial class approach and Base
class approach.
Let's see both of them in action.
Partial class
In this approach you create a partial class matching the name of the
component. For example, the Counter component exists in Component.razor file.
So, you need to create a partial class called Counter. Then you need to write
all the C# code into the partial class. The UI markup will remain in the
Counter.razor file.
Here, we will create a new component and copy the code from Counter component
into it. This way we can test all the approaches in a single project.
Add a new Razor Component named Counter1.razor using Add New Item dialog.
Then add a new C# class file called Counter1.razor.cs.
The name of the class file can be anything but if you stick to this
convention Visual Studio will show it as a nested file of Counter1.razor.
Now copy the UI code from Counter.razor into Counter1.razor file.
@page "/counter1"
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary"
@onclick="IncrementCount">
Click me
</button>
Note that after coping the code we change the @page directive to /counter1 to
avoid duplicate routes.
Then copy everything from the @code block of Counter.razor to
Counter1.razor.cs. This is shown below:
public partial class Counter1
{
private int currentCount = 0;
private void IncrementCount()
{
currentCount++;
}
}
Notice that Counter1 class is marked to be a partial class.
We just created Counter1 component that separates its UI and C# code into
different files.
Base class
Let's see the base class approach. This approaches also involves a .razor
file and a corresponding .cs file but rather than creating a partial class we
resort to inheritance.
Add another Razor Component called Counter2.razor. Also add a new C# class
file called Counter2.razor.cs.
Now open the Counter2.razor.cs file and write the following class definition
into it.
public class Counter2Base : ComponentBase
{
protected int currentCount = 0;
protected void IncrementCount()
{
currentCount++;
}
}
Notice that the class name is Counter2Base and it inherits from ComponentBase
class. This class name can be anything. But to avoid any ambiguity with the
Counter2, we call it Counter2Base.
Also notice that the class members are changed from private to protected.
This is required because we are going to use inheritance (rather than partial
class) in this example.
Now modify the Counter2.razor file as shown below:
@page "/counter2"
@inherits Counter2Base
<h1>Counter</h1>
<p>Current count: @currentCount</p>
<button class="btn btn-primary"
@onclick="IncrementCount">
Click me
</button>
As before we assign some different route to this component. Moreover,
Counter2 component inherits from Counter2Base class. This is indicated using
@inherits directive.
Now, let's see whether all the three components work as expected.
Open NavMenu.razor file and add two menu entries for the two additional
components we created.
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter">
<span class="oi oi-plus" aria-hidden="true">
</span> Counter
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter1">
<span class="oi oi-plus" aria-hidden="true">
</span> Counter1
</NavLink>
</li>
<li class="nav-item px-3">
<NavLink class="nav-link" href="counter2">
<span class="oi oi-plus" aria-hidden="true">
</span> Counter2
</NavLink>
</li>
Run the project and navigate to all the three "counter" components from the
left side menu.
Click on the "Click me" button of each counter component and check whether it
displays the correct value.
That's it for now! Keep coding!!