Intro
This time, I try CSS isolatio and creating child conponents in a component.
Environments
- .NET ver.5.0.101
Base Project
I create a project like them.
I use ASP.NET Core MVC and Blazor Server.
HomeController.cs
using System;
using Microsoft.AspNetCore.Mvc;
namespace BlazorSample.Controllers
{
public class HomeController: Controller
{
[Route("")]
[Route("{page}")] // <- DON'T DO THIS for CSS Isolation
public ActionResult OpenPage(string page)
{
ViewData["Title"] = $"Page {page}";
return View("Views/_Host.cshtml");
}
}
}
_Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@ViewData["Title"]</title>
<base href="~/" />
</head>
<body>
@RenderBody()
<script src="_framework/blazor.server.js"></script>
</body>
</html>
_Host.cshtml
@namespace BlazorSample.Views
@(await Html.RenderComponentAsync<App>(RenderMode.ServerPrerendered))
App.razor
@using Shared
<Router AppAssembly="@typeof(Program).Assembly" PreferExactMatches="@true">
<Found Context="routeData">
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
MainLayout.razor
@inherits LayoutComponentBase
@Body
DisplayGridPage.razor
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<div id="sheet_area">
</div>
CSS Isolation
From .NET 5, I can create CSS files for each Blazor files.
I have to do these two things.
1.Add CSS link to {ProjectName}.styles.css in _Layout.cshtml or _Host.cshtml.
2.Add {BlazorFileName}.css. For example, if Blazor file name is "DisplayGridPage.razor", the CSS file name is "DisplayGridPage.razor.css".
_Layout.cshtml
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>@ViewData["Title"]</title>
<base href="~/" />
<!-- When the page is loaded, the content of CSS will be changed -->
<link href="BlazorSample.styles.css" rel="stylesheet" />
</head>
<body>
@RenderBody()
<script src="_framework/blazor.server.js"></script>
</body>
</html>
DisplayGridPage.razor.css
#sheet_area
{
height: 30vh;
width: 30vw;
background-color: aqua;
display: grid;
}
h1{
color: blue;
}
Get HTML named CSS?
Unfortunately, the CSS wasn't work.
Because in the Controller class, I routed "localhost:5000/" and "localhost:5000/{page}" to return View.
So "localhost:5000/BlazorSample.styles.css" was also treated as View.
Though I might be able to resolve by using middleware, I decided change the route.
HomeController.cs
...
namespace BlazorSample.Controllers
{
public class HomeController: Controller
{
[Route("")]
[Route("Pages/{page}")]
public ActionResult OpenPage(string page)
...
Generated CSS
When I add CSS for MainLayout.razor, the CSS for DisplayGridPage.razor will be generated from MainLayout.razor.css and DisplayGridPage.razor.css
/* _content/BlazorSample/Views/DisplayGridPage.razor.rz.scp.css */
#sheet_area[b-p832tuedyv]
{
height: 30vh;
width: 30vw;
background-color: aqua;
display: grid;
}
h1[b-p832tuedyv]{
color: blue;
}
/* _content/BlazorSample/Views/Shared/MainLayout.razor.rz.scp.css */
h1[b-m6a6nzx0h4]{
color: red;
}
header[b-m6a6nzx0h4]{
background-color: rosybrown;
}
Using components
Next, I try add child components.
There is no any special way to create and add child components.
1.Create Blazor files(.razor, .razor.cs, .razor.css)
Cell.razor
<div class="cell_frame">Hello cell</div>
Cell.razor.cs
using Microsoft.AspNetCore.Components;
namespace BlazorSample.Views.Components
{
public partial class Cell
{
}
}
Cell.razor.css
.cell_frame{
background-color: gray;
border: 1px solid black;
color: goldenrod;
}
2.Add 1. into the parent component as a HTML element.
DisplayGridPage.razor
@page "/"
<h1>Hello, world!</h1>
Welcome to your new app.
<div id="sheet_area">
@for(var i = 1; i <= 3; i++){
<BlazorSample.Views.Components.Cell></BlazorSample.Views.Components.Cell>
}
</div>
Result
Child component's CSS
In this sample, "BlazorSample.styles.css" includes "MainLayout.razor.css" and "DisplayGridPage.razor.css".
How about "Cell.razor.css" ?
All of them are merged and added into "BlazorSample.styles.css".
BlazorSample.styles.css
/* _content/BlazorSample/Views/Components/Cell.razor.rz.scp.css */
.cell_frame[b-64je09gotq]{
background-color: gray;
border: 1px solid black;
color: goldenrod;
}
/* _content/BlazorSample/Views/Components/SheetSelector.razor.rz.scp.css */
/* _content/BlazorSample/Views/DisplayGridPage.razor.rz.scp.css */
#sheet_area[b-p832tuedyv]
{
height: 30vh;
width: 30vw;
background-color: aqua;
display: grid;
}
h1[b-p832tuedyv]{
color: blue;
}
/* _content/BlazorSample/Views/Shared/MainLayout.razor.rz.scp.css */
h1[b-m6a6nzx0h4]{
color: red;
}
header[b-m6a6nzx0h4]{
background-color: rosybrown;
}
Set values from the parent
When I want to set values into the child components, I can add parameters into them.
Cell.razor.cs
using System;
using Microsoft.AspNetCore.Components;
namespace BlazorSample.Views.Components
{
public partial class Cell
{
[Parameter]
public int Index { get; set; }
[Parameter]
public BlazorSample.Spreadsheets.Cell CellValue{ get; set; }
}
}
Cell.razor
<div class="cell_frame" id="cell_@Index">Hello cell@(Index)</div>
DisplayGridPage.razor.cs
...
public partial class DisplayGridPage
{
[Parameter]
public List<BlazorSample.Spreadsheets.Cell> Cells { get; set; }
public DisplayGridPage()
{
Cells = new List<Cell>
{
new Cell(1, 1, "Hello"),
new Cell(1, 2, "World"),
};
}
...
DisplayGridPage.razor
...
<div id="sheet_area">
@code
{
int index = 1;
}
@foreach (var cell in Cells)
{
<BlazorSample.Views.Components.Cell Index="index" CellValue="cell">
</BlazorSample.Views.Components.Cell>
index += 1;
}
</div>
...
When the parameter values will be set?
When the constructor is called, the parameters has not been set their values.
If I want to do something on initializing, I have to override Blazor event methods.
Cell.razor.cs
...
public partial class Cell
{
[Parameter]
public int Index { get; set; }
[Parameter]
public BlazorSample.Spreadsheets.Cell CellValue{ get; set; }
public Cell()
{
// the values haven't set yet.
// Output: [Constructor] CellValue Index: 0 Cell?:True
Console.WriteLine($"[Constructor] CellValue Index: {Index} Cell?:{CellValue == null}" );
}
protected override void OnInitialized()
{
// Output: [Init] CellValue Index: 1 Cell?:False
Console.WriteLine($"[Init] CellValue Index: {Index} Cell?:{CellValue == null}" );
}
}
...
I think Blazor's grammer is similar to Angular.
Callback
I can use "EventCallback" to call from child components to the parent component.
Cell.razor.cs
...
public partial class Cell
{
...
[Parameter]
public EventCallback<string> OnCellClicked { get; set; }
public async Task OnClick()
{
await OnCellClicked.InvokeAsync();
}
}
...
DisplayGridPage.razor
...
@foreach (var cell in Cells)
{
<BlazorSample.Views.Components.Cell Index="index" CellValue="cell"
OnCellClicked="@((message) => Console.WriteLine(message))">
</BlazorSample.Views.Components.Cell>
index += 1;
}
...
Escape "" in Blazor
I can use two ways to use ""(double quotations) in Blazor files.
<!-- Use @() -->
<BlazorSample.Views.Components.Cell Index="index" CellValue="cell"
OnCellClicked="@(_ => Console.WriteLine("World"))">
</BlazorSample.Views.Components.Cell>
<!-- Use ''(single quotations) -->
<BlazorSample.Views.Components.Cell Index="index" CellValue="cell"
OnCellClicked='_ => Console.WriteLine("World")'>
</BlazorSample.Views.Components.Cell>
Call child components' methods
I can control child components' instances by @ref.
Cell.razor.cs
...
public partial class Cell
{
...
public void Greet()
{
Console.WriteLine("Hello World!");
}
...
DisplayGridPage.razor
...
<BlazorSample.Views.Components.Cell Index="10"
CellValue='new BlazorSample.Spreadsheets.Cell(10, 10, "HelloWorld")'
OnCellClicked='_ => Console.WriteLine("World")' @ref="cell">
</BlazorSample.Views.Components.Cell>
</div>
<button @onclick="ClickSample">Click</button>
@code
{
BlazorSample.Views.Components.Cell cell;
void ClickSample()
{
cell.Greet();
}
}
Resources
CSS
- ASP.NET Core Blazor CSS isolation | Microsoft Docs
- How to ignore routes in ASP.NET Core? - Stack Overflow
- Use CSS isolation in your Blazor projects | Dave Brock
Top comments (0)