rksoftware

Visual Studio とか C# とかが好きです

Blazor Hybrid (Windows フォーム) プロジェクトの作り方

Blazor には 7 つのプロジェクト タイプがあります。

今回は少し複雑なな Blazor Hybrid (Windows フォーム) プロジェクトを作ってみたいと思います。

参考

docs.microsoft.com

■ dotnet command

コマンドで作成すると手ばやいです。

> dotnet new winforms -o BlazorWinFormsSample
> cd .\BlazorWinFormsSample\

□ .csproj ファイルの編集

少し複雑なので .csproj ファイルを編集します。
テキストエディタで .csproj ファイルを開きます (ここではメモ帳で開いています)。

> notepad .\BlazorWinFormsSample.csproj

開いたファイルは次のようになっています。

<Project Sdk="Microsoft.NET.Sdk">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

</Project>

この先頭の Sdk 部分を Microsoft.NET.Sdk.Razor と変更します。

<Project Sdk="Microsoft.NET.Sdk.Razor">

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWindowsForms>true</UseWindowsForms>
    <ImplicitUsings>enable</ImplicitUsings>
  </PropertyGroup>

</Project>

□ Blazor ソースファイルを作成

プロジェクト内に Blazor 部分となる 4 つのソースファイルを追加します。

mkdir wwwroot
mkdir wwwroot\css
"@using Microsoft.AspNetCore.Components.Web"  | Out-File -Encoding utf8 _Imports.razor
"<!DOCTYPE html>`n<html lang=`"en`">`n<head>`n    <meta charset=`"utf-8`" />`n    <meta name=`"viewport`" content=`"width=device-width, initial-scale=1.0`" />`n    <title>WinFormsBlazor</title>`n    <base href=`"/`" />`n    <link href=`"css/app.css`" rel=`"stylesheet`" />`n    <link href=`"WinFormsBlazor.styles.css`" rel=`"stylesheet`" />`n</head>`n`n<body>`n`n    <div id=`"app`">Loading...</div>`n`n    <div id=`"blazor-error-ui`">`n        An unhandled error has occurred.`n        <a href=`"`" class=`"reload`">Reload</a>`n        <a class=`"dismiss`">🗙</a>`n    </div>`n`n    <script src=`"_framework/blazor.webview.js`"></script>`n`n</body>`n`n</html>" | Out-File -Encoding utf8 wwwroot/index.html
"html, body {`n    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;`n}`n`n.valid.modified:not([type=checkbox]) {`n    outline: 1px solid #26b050;`n}`n`n.invalid {`n    outline: 1px solid red;`n}`n`n.validation-message {`n    color: red;`n}`n`n#blazor-error-ui {`n    background: lightyellow;`n    bottom: 0;`n    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);`n    display: none;`n    left: 0;`n    padding: 0.6rem 1.25rem 0.7rem 1.25rem;`n    position: fixed;`n    width: 100%;`n    z-index: 1000;`n}`n`n    #blazor-error-ui .dismiss {`n        cursor: pointer;`n        position: absolute;`n        right: 0.75rem;`n        top: 0.5rem;`n    }"  | Out-File -Encoding utf8 wwwroot/css/app.css
"<h1>Counter</h1>`n`n<p>Current count: @currentCount</p>`n`n<button class=`"btn btn-primary`" @onclick=`"IncrementCount`">Click me</button>`n`n@code {`n    private int currentCount = 0;`n`n    private void IncrementCount()`n    {`n        currentCount++;`n    }`n}"  | Out-File -Encoding utf8 Counter.razor

次の 4 ファイルが作れているはずです。
ここで行っているファイル作成方法については次の記事に。

rksoftware.hatenablog.com

□ 出来上がったファイル

_Imports.razor

@using Microsoft.AspNetCore.Components.Web

wwwroot/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>WinFormsBlazor</title>
    <base href="/" />
    <link href="css/app.css" rel="stylesheet" />
    <link href="WinFormsBlazor.styles.css" rel="stylesheet" />
</head>

<body>

    <div id="app">Loading...</div>

    <div id="blazor-error-ui">
        An unhandled error has occurred.
        <a href="" class="reload">Reload</a>
        <a class="dismiss">🗙</a>
    </div>

    <script src="_framework/blazor.webview.js"></script>

</body>

</html>

wwwroot/css/app.css

html, body {
    font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
}

.valid.modified:not([type=checkbox]) {
    outline: 1px solid #26b050;
}

.invalid {
    outline: 1px solid red;
}

.validation-message {
    color: red;
}

#blazor-error-ui {
    background: lightyellow;
    bottom: 0;
    box-shadow: 0 -1px 2px rgba(0, 0, 0, 0.2);
    display: none;
    left: 0;
    padding: 0.6rem 1.25rem 0.7rem 1.25rem;
    position: fixed;
    width: 100%;
    z-index: 1000;
}

#blazor-error-ui .dismiss {
    cursor: pointer;
    position: absolute;
    right: 0.75rem;
    top: 0.5rem;
}

Counter.razor

<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++;
    }
}

□ 画面のコードを編集

画面のコードを開きます。

> notepad .\Form1.cs

開いたファイルの先頭に 2 つの using を追加します。

using Microsoft.AspNetCore.Components.WebView.WindowsForms;
using Microsoft.Extensions.DependencyInjection;

一つの読み取り専用プロパティを追加します。

BlazorWebView blazorWebView1 { get; };

コンストラクタにコントロールの追加とコントロールへの設定を追加します。Windows フォームのコントロールはシンプルなのでコードだけで UI が作りやすくて直感的ですね。

this.Controls.Add(blazorWebView1 = new BlazorWebView{
    Dock = DockStyle.Fill
});

var services = new ServiceCollection();
services.AddWindowsFormsBlazorWebView();
blazorWebView1.HostPage = "wwwroot\\index.html";
blazorWebView1.Services = services.BuildServiceProvider();
blazorWebView1.RootComponents.Add<Counter>("#app");

ファイルはこんな感じになります。

Form1.cs

using Microsoft.AspNetCore.Components.WebView.WindowsForms;
using Microsoft.Extensions.DependencyInjection;

namespace BlazorWinFormsSample;

public partial class Form1 : Form
{
    BlazorWebView blazorWebView1 { get; }

    public Form1()
    {
       InitializeComponent();

        this.Controls.Add(blazorWebView1 = new BlazorWebView{
            Dock = DockStyle.Fill
        });

        var services = new ServiceCollection();
        services.AddWindowsFormsBlazorWebView();
        blazorWebView1.HostPage = "wwwroot\\index.html";
        blazorWebView1.Services = services.BuildServiceProvider();
        blazorWebView1.RootComponents.Add<Counter>("#app");
    }
}

□ NuGet パッケージのインストール

prerelease 版の NuGet パッケージをインストールします。

> dotnet add package Microsoft.AspNetCore.Components.WebView.WindowsForms --prerelease

□ 実行

実行はプロジェクト ファイル (.csproj) のある場所で dotnet run

> dotnet run

Windows フォームアプリの中で Blazor が動きました。

これで Blazor Hybrid (Windows フォーム) のプロジェクトを作成して実行することができました。

■ Visual Studio

ワークロード .NET デスクトップ開発 が必要です。

Visual Studio の場合はプロジェクトの作成から。



プロジェクト (ソリューション) が作成され、Visual Studio で開かれます。

プロジェクトファイルを編集します。



コマンドラインの時と同様に Blazor の 4 ファイルを追加します。

フォームのソースも同様に編集します。



NuGet パッケージを追加します。プレリリースを含める のチェックを忘れないでください。

デバッグ実行で Windows フォームアプリの中で Blazor が動きました。

■ 簡単ですね

簡単ですね。