Blazor Advent Calendar 2019 の記事です。今回は、Blazor Server-Sideで遠隔操作できるペンライトアプリケーションを作ってみたいと思います。ライブ会場で販売されている同期するペンライトのスマホ版です。
Blazor Server-Sideアプリケーションにより、特定のページ(URL)に接続されたスマホの画面を遠隔で操作できるようにしたいと思います。
作成イメージ 左:管理画面 右:接続されたスマホの画面(実際の画面は遅延なし)
スタイルを動的に変更する
Blazorではタグ内に、動的変数を使用できます。つまり、classセレクタ
やstyle
の内容を動的に変更できるのです。値変更後も、StateHasChangedメソッド
を呼ぶことで、DOMが再構成されページが生成されます。この仕組みで、CSS
の変更だけでなく、コントロールなども動的に生成することができるので、こういったところはJavaScriptレス
に書くことができて、Blazorのワクワクする部分ですね!
classセレクタ や styleを返す
<div class=@GetClass style=@GetStyle>
</div>
@code{
bool alarm = false;
string GetClass()
{
return "main";
}
string GetStyle()
{
if(alarm)
{
return "warn";
}
else
{
return "normal";
}
}
}
こんな書き方もOK
cssファイル内のスタイルを変更することはできませんが、インラインで書かれたstyle
の内容であれば動的にセットすることができます。
<style>
.test{
@styleStr
}
</style>
<div class="test">
<p>Hello World</p>
</div>
@code{
string styleStr = "color:black;";
void SetColor(string colorName)
{
styleStr = "color:" + colorName + ";";
}
}
この特性を活かし、ショートコーディングでパリピなアプリを作っていきたいと思います。
色管理クラス
全セッションで共有される色だけを保持するクラスを作ります。状態変化で任意のイベントを実行できるようにハンドラを用意しておきます。
public class ColorClass
{
private string _colorStr = "";
public string ColorStr
{
get
{
return _colorStr;
}
set
{
_colorStr = value;
this.StateChanged?.Invoke(this, EventArgs.Empty);
}
}
public event EventHandler StateChanged;
}
Startup.csの編集
色管理クラスをプログラムの起動時にシングルトンで生成させます。
public class Startup
{
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddRazorPages();
services.AddServerSideBlazor();
services.AddSingleton<WeatherForecastService>();
//シングルトンでインスタンスを生成
services.AddSingleton<ColorClass>();
}
}
#MainLayout.razorの編集
MainLayout.razor
は余計なものを取り、@Body
だけ表示させます。色管理クラスをInject
し、初回に値の変更を契機にStateHasChangedメソッド
をコールし画面の再生成をするように仕掛けておきます。
@inherits LayoutComponentBase
@inject ColorClass colorCls;
@*子コンテンツにカスケードでインスタンスを渡す*@
<CascadingValue Value="@colorCls" Name="Color">
@Body
</CascadingValue>
@code{
protected override void OnInitialized()
{
//値変更で、画面の再生成を行う
colorCls.StateChanged += (s,e) =>
{
this.InvokeAsync(this.StateHasChanged);
};
}
}
色を変更できる画面(Manage.razor)
色を変更できる管理画面を作成します。ここでは、/manage
でアクセスすると、この画面が表示されるようにします。
id:main
に対し、background-Color
を変化させることにより、ページ全体の背景色を動的に変化できるようにします。
@page "/manage"
<div id="main" style=@colorClass.ColorStr>
<div class="content-row">
@foreach(var colorName in ColorNames)
{
<button class="btn " style="background-color:@colorName;width:150px"
@onclick=@(_=>SetStyle(colorName))>@colorName</button>
}
</div>
</div>
@code
{
[CascadingParameter(Name="Color")]
protected ColorClass colorClass { get; set; }
string[] ColorNames = new string[0];
protected override void OnInitialized()
{
// ConsoleColorから色名を取得
ColorNames = Enum.GetNames(typeof(ConsoleColor));
}
void SetStyle(string name)
{
// ここの変更で、背景色が変わる
colorClass.ColorStr = "background-Color:" + name;
}
}
クライアント画面(Index.razor)
操作される側は、/
でアクセスされたときに表示される画面です。管理画面と同じく、ID:main
に対しbackground-Color
を動的に変更できるようにします。
@page "/"
<div id="main" style=@colorClass.ColorStr>
</div>
@code
{
[CascadingParameter(Name="Color")]
protected ColorClass colorClass { get; set; }
}
#最後に
Blazor Server-Sideアプリケーションは、SignalR
により常時セッションが張られ状態変化が起きる度にデータの転送が行われていますが、変化が行われた箇所のみ送信されるので、その転送量は大きくありません。例えば、このアプリケーションの場合、色の変化によって1つの接続先に転送される情報量は約100Byte程度のものでした。
今回は、一見するとJavaScript
を使ったアプリケーションに見えますが、JavaScriptレス
で書くことができました!また、驚くほどコーディング量も少ないところがBlazorの良いところですね