Page 60 - MSDN Magazine, September 2018
P. 60
The router is responsible for inter- cepting all navigation activity, both inward and outward, and making it happen. Clearly, Blazor components are expected to provide routing infor- mation for the router to invoke them appropriately. Blazor supports the same @page notation of Razor Pages in ASP.NET Core. In addition, it supports the Route attribute for component classes written in plain C#.
The Single Page
Usually, a single-page application starts from an index.html page. A Blazor application is no exception, and the sin- gle page is located under the wwwroot folder. The single page is expected to containatleastthefollowingmarkup:
<app>
<!—initialization markup -->
</app>
<script src="_framework/blazor. webassembly.js"></script>
The content of the app element is displayed during the initial loading of the Blazor platform, namely the first chunk of files in the list of Figure 2. You can have any valid HTML in the app element, most commonly a loading .gif. The script element is responsi- ble for dynamically downloading the necessary .dll files.
The actual displayed content of the homepage is determined by the router and the remaining content of the index.html file found following the script element. Let’s review the work done by the router.
The router checks the requested URL—the root of the deployed site— and looks for a registered component that can match the root URL. In the sample project, the Pages folder con- tains an index.cshtml file that begins with the following content:
@page "/"
<h1>Hello, Blazor!</h1>
Welcome to your first BLAZOR app.
The @page directive instructs the router about the template to pick up. If a _ViewImports.cshtml file is found in the Pages folder (and/or the root folder), its content is taken into account. In the sample project, the _ViewImports file in root folder contains a list of using statements, while the _ViewImports
Figure 3 C# Code of the DigitalClock Component
file in the Pages folder contains a ref- erence to the layout template:
@layout MainLayout
Subsequently, the content of the MainLayout.cshtml is processed and the @Body placeholder populated with the output of the selected Razor view (index.cshtml). In the sample project, the layout file (found in the Shared folder, as in ASP.NET Core) contains a typical Bootstrap 4 dark navbar element. Here’s that code:
<nav class="navbar navbar-expand-lg navbar-dark bg-dark">
...
</nav>
<div class="container">
@Body </div>
Again, if you’re coming from an ASP.NETMVCbackground,thispro- gramming pattern should look pretty familiar. In the navbar you typically have links.Youcanexpresslinksthroughthe canonical A and BUTTON elements, or use one of the predefined (or cus- tom) Razor tag helpers. In particular, Blazor comes with the NavLink helper component, which provides a friendlier syntax to express links that may or may not be plain URLs. In a single-page application, in fact, a link can be any- thing that the router can understand. Here’s a fragment of Razor code used in the navbar of the sample application:
<div class="collapse navbar-collapse" id="navbarNav">
<ul class="navbar-nav">
<NavLink class="nav-link" href="digitalclock"> DIGITAL CLOCK
</NavLink> </ul>
</div>
The href attribute points to a URI that can just match the route to a component like “digitalclock,” a separate CSHTML file that fully implements a digital clock component. The digitalclock.cshtml file is found under the Pages folder.
Building a Sample
Component
A Blazor component is a self-contained chunk of HTML and C#. Any necessary CSS goes in separate files, reasonably named after the component itself. Note that Blazor doesn’t do anything special with CSS and doesn’t impose any convention. Dealing with CSS is
@functions {
string currentTime = "N/A";
string buttonAction = "N/A"; string currentCss = "clock-notset"; Timer timer;
protected override async Task OnInitAsync() {
InitTimer();
StartTimer(); }
void startStop() {
if (timer.Enabled) {
StopTimer(); }
else {
StartTimer(); }
}
private Task TimerTick() {
currentTime = DateTime.Now.ToLongTimeString(); currentCss = "clock-working"; this.StateHasChanged();
return Task.CompletedTask; }
private void InitTimer() {
timer = new Timer(1000);
timer.Elapsed += async (sender, e) => await TimerTick(); }
private void StartTimer() {
buttonAction = "STOP";
timer.Start(); }
private void StopTimer() {
buttonAction = "START";
timer.Stop(); }
}
52 msdn magazine
Cutting Edge
Figure 4 The Sample Application in Action