8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

BlazorAdvent Calendar 2019

Day 21

Blazor Server-Sideで作るペンライトアプリ

Last updated at Posted at 2019-12-20

Blazor Advent Calendar 2019 の記事です。今回は、Blazor Server-Sideで遠隔操作できるペンライトアプリケーションを作ってみたいと思います。ライブ会場で販売されている同期するペンライトのスマホ版です。

Blazor Server-Sideアプリケーションにより、特定のページ(URL)に接続されたスマホの画面を遠隔で操作できるようにしたいと思います。

作成イメージ 左:管理画面 右:接続されたスマホの画面(実際の画面は遅延なし)
xp828-yvk4c.gif
group_people_smartphone_no_dog.png

スタイルを動的に変更する

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の編集

色管理クラスをプログラムの起動時にシングルトンで生成させます。

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メソッドをコールし画面の再生成をするように仕掛けておきます。

MainLayout.razor
@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を変化させることにより、ページ全体の背景色を動的に変化できるようにします。

Manage.razor
@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を動的に変更できるようにします。

Index.razor
@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の良いところですね:thumbsup:

8
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?