最新記事=> Blazor Server 使い勝手の良い MessageBox v2
Windows Form アプリの MessageBox と同等の使い勝手で、使い勝手の良い MessageBox を Blazor Server でも実現したので使ってほしい。
ソースコードはGitHubで公開しています。
ソースコード構成
ソースコード変更内容を解説
WebApplication1.csproj
・Blazored.Modal nugetパッケージを追加。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
<Project Sdk="Microsoft.NET.Sdk.Web"> <PropertyGroup> <TargetFramework>net5.0</TargetFramework> </PropertyGroup> <ItemGroup> <PackageReference Include="Blazored.Modal" Version="6.0.1" /> </ItemGroup> </Project> |
_Imports.razor
・Blazored.Modal、Blazored.Modal.Services の usingを追加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@using System.Net.Http @using Microsoft.AspNetCore.Authorization @using Microsoft.AspNetCore.Components.Authorization @using Microsoft.AspNetCore.Components.Forms @using Microsoft.AspNetCore.Components.Routing @using Microsoft.AspNetCore.Components.Web @using Microsoft.AspNetCore.Components.Web.Virtualization @using Microsoft.JSInterop @using Blazored.Modal @using Blazored.Modal.Services @using WebApplication1 @using WebApplication1.Shared |
App.razor
・<CascadingBlazoredModal>を追加。一番外側に追加すればどこからでも使える。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
<CascadingBlazoredModal> <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> </CascadingBlazoredModal> |
Pages/_Host.cshtml
・Blazored.Modal nugetパッケージに組み込まれている、blazored-modal.css blazored.modal.js を追加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
@page "/" @namespace WebApplication1.Pages @addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers @{ Layout = null; } <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <title>WebApplication1</title> <base href="~/" /> <link rel="stylesheet" href="css/bootstrap/bootstrap.min.css" /> <link href="css/site.css" rel="stylesheet" /> <link href="WebApplication1.styles.css" rel="stylesheet" /> <link href="_content/Blazored.Modal/blazored-modal.css" rel="stylesheet" /> </head> <body> <component type="typeof(App)" render-mode="ServerPrerendered" /> <div id="blazor-error-ui"> <environment include="Staging,Production"> An error has occurred. This application may no longer respond until reloaded. </environment> <environment include="Development"> An unhandled exception has occurred. See browser dev tools for details. </environment> <a href="" class="reload">Reload</a> <a class="dismiss">🗙</a> </div> <script src="_framework/blazor.server.js"></script> <script src="_content/Blazored.Modal/blazored.modal.js"></script> </body> </html> |
Startup.cs
・Blazored.Modal の using と、services.AddBlazoredModal() を追加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Components; using Microsoft.AspNetCore.Hosting; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Blazored.Modal; using WebApplication1.Data; namespace WebApplication1 { public class Startup { public Startup(IConfiguration configuration) { Configuration = configuration; } public IConfiguration Configuration { get; } // 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.AddBlazoredModal(); } // This method gets called by the runtime. Use this method to configure the HTTP request pipeline. public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } else { app.UseExceptionHandler("/Error"); } app.UseStaticFiles(); app.UseRouting(); app.UseEndpoints(endpoints => { endpoints.MapBlazorHub(); endpoints.MapFallbackToPage("/_Host"); }); } } } |
Shared/NavMenu.razor
・MessageBoxSample 画面へのリンクを追加。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
<div class="top-row pl-4 navbar navbar-dark"> <a class="navbar-brand" href="">WebApplication1</a> <button class="navbar-toggler" @onclick="ToggleNavMenu"> <span class="navbar-toggler-icon"></span> </button> </div> <div class="@NavMenuCssClass" @onclick="ToggleNavMenu"> <ul class="nav flex-column"> <li class="nav-item px-3"> <NavLink class="nav-link" href="" Match="NavLinkMatch.All"> <span class="oi oi-home" aria-hidden="true"></span> Home </NavLink> </li> <li class="nav-item px-3"> <NavLink class="nav-link" href="counter"> <span class="oi oi-plus" aria-hidden="true"></span> Counter </NavLink> </li> <li class="nav-item px-3"> <NavLink class="nav-link" href="fetchdata"> <span class="oi oi-list-rich" aria-hidden="true"></span> Fetch data </NavLink> </li> <li class="nav-item px-3"> <NavLink class="nav-link" href="MessageBoxSample"> <span class="oi oi-plus" aria-hidden="true"></span> MessageBox Sample </NavLink> </li> </ul> </div> @code { private bool collapseNavMenu = true; private string NavMenuCssClass => collapseNavMenu ? "collapse" : null; private void ToggleNavMenu() { collapseNavMenu = !collapseNavMenu; } } |
MessageBoxの左側に表示しているフリー素材のアイコンを追加
wwwroot/img/MessageIcon/Error.jpg
wwwroot/img/MessageIcon/Information.jpg
wwwroot/img/MessageIcon/Question.jpg
wwwroot/img/MessageIcon/Warning.jpg
enumを追加
Const/enums/MessageBoxButtons.cs
Const/enums/MessageBoxIcon.cs
Modal/ModalMessageBox.razor
・ MessageBox の画面本体。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 |
@using WebApplication1; @inject IModalService ModalService <div> <table> <tbody> <tr> <td width="90"> @if (Icon == MessageBoxIcon.Information) { <img width="70" src="img/MessageIcon/Information.jpg" /> } else if (Icon == MessageBoxIcon.Question) { <img width="70" src="img/MessageIcon/Question.jpg" /> } else if (Icon == MessageBoxIcon.Warning) { <img width="70" src="img/MessageIcon/Warning.jpg" /> } else if (Icon == MessageBoxIcon.Error) { <img width="70" src="img/MessageIcon/Error.jpg" /> } </td> <td> @if (Message.IndexOf("\r\n") < 0) { <p>@Message</p> } else { <p> @foreach (var textRow in Message.Split("\r\n")) { <span>@textRow</span><br> } </p> } @if (!string.IsNullOrEmpty(MessageDetail)) { <div class="messagebox-detailmessage"> @if (MessageDetail.IndexOf("\r\n") < 0) { <p>@MessageDetail</p> } else { <p> @foreach (var textRow in MessageDetail.Split("\r\n")) { <span>@textRow</span><br> } </p> } </div> } </td> </tr> </tbody> </table> <p><br></p> @if (Buttons == MessageBoxButtons.YesNo) { <div class="right"> <button @onclick="Yes" class="btn btn-primary"> はい </button><span> </span> <button @onclick="No" class="btn btn-secondary"> いいえ </button> </div> } else if (Buttons == MessageBoxButtons.OK) { <button @onclick="Ok" class="btn btn-primary messagebox-btn"> OK </button> } </div> @code { [CascadingParameter] BlazoredModalInstance BlazoredModal { get; set; } [Parameter] public string Message { get; set; } [Parameter] public string MessageDetail { get; set; } [Parameter] public MessageBoxButtons Buttons { get; set; } [Parameter] public MessageBoxIcon Icon { get; set; } async Task Yes() => await BlazoredModal.CloseAsync(ModalResult.Ok(true)); async Task No() => await BlazoredModal.CancelAsync(); async Task Ok() => await BlazoredModal.CancelAsync(); } |
Modal/ModalMessageBox.razor.css
・MessageBox 画面のcss。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 |
table { border-collapse: collapse; border-color: var(--tableborder-color); border: solid 0px; width: 100%; word-break: break-all; word-break: break-word; } thead { vertical-align: middle !important; } th { padding: 5px 10px !important; vertical-align: middle !important; font-weight: bold; border: solid 0px !important; border-bottom: dotted 0px; color: var(--head-color); background-color: var(--tableth-color); border-color: #3C8065; } td { padding: 5px 10px !important; vertical-align: middle; border: solid 0px !important; border-color: var(--tableborder-color); background-color: white; } .caption-title { caption-side: top; font-size: 1.1rem; color: var(--head-color); font-weight: bold; padding-bottom: 1px; } |
Common/MessageBox.cs
・アプリ全体から MessageBox 画面を表示するための処理。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
using System; using System.Collections.Generic; using System.Linq; using System.IO; using System.Threading.Tasks; using Microsoft.Extensions.Logging; using Microsoft.AspNetCore.Components; using Blazored.Modal; using Blazored.Modal.Services; using WebApplication1.Modal; namespace WebApplication1 { /// <summary> /// Windows Form の MessageBoxリスペクト クラス /// </summary> public class MessageBox { private IModalService Modal; public MessageBox(IModalService modal) { Modal = modal; } /// <summary> /// 確認画面表示 /// </summary> public async Task<ModalResult> Show(string caption, string text, MessageBoxButtons buttons, MessageBoxIcon icon) { var parameters = new ModalParameters(); parameters.Add(nameof(ModalMessageBox.Message), text); parameters.Add(nameof(ModalMessageBox.MessageDetail), null); parameters.Add(nameof(ModalMessageBox.Buttons), buttons); parameters.Add(nameof(ModalMessageBox.Icon), icon); var moviesModal = Modal.Show<ModalMessageBox>(caption, parameters); var result = await moviesModal.Result; return result; } public async Task<ModalResult> Show(string caption, string text, string textDetail, MessageBoxButtons buttons, MessageBoxIcon icon) { var parameters = new ModalParameters(); parameters.Add(nameof(ModalMessageBox.Message), text); parameters.Add(nameof(ModalMessageBox.MessageDetail), textDetail); parameters.Add(nameof(ModalMessageBox.Buttons), buttons); parameters.Add(nameof(ModalMessageBox.Icon), icon); var moviesModal = Modal.Show<ModalMessageBox>(caption, parameters); var result = await moviesModal.Result; return result; } } } |
Pages/MessageBoxSample.razor
・MessageBox を使っているサンプル画面。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
@page "/MessageBoxSample" <br> <button class="btn btn-primary" @onclick="Message1">確認メッセージ + 完了メッセージ</button> <br> <br> <button class="btn btn-primary" @onclick="Message2">完了メッセージ</button> <br> <br> <button class="btn btn-primary" @onclick="Message3">完了メッセージ 詳細メッセージ有り</button> <br> <br> <button class="btn btn-primary" @onclick="Message4">警告メッセージ</button> <br> <br> <button class="btn btn-primary" @onclick="Message5">エラーメッセージ</button> <br> @code { private int currentCount = 0; [CascadingParameter] public IModalService Modal { get; set; } private async Task Message1() { var result = await (new MessageBox(Modal)).Show("確認", "登録しますか?\r\n\r\n詳細があれば・・・", MessageBoxButtons.YesNo, MessageBoxIcon.Question); if (result.Cancelled) { return; } // 正常終了 await (new MessageBox(Modal)).Show("完了", $"〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇が完了しました。", MessageBoxButtons.OK, MessageBoxIcon.Information); } private async Task Message2() { await (new MessageBox(Modal)).Show("完了", $"〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇が完了しました。", MessageBoxButtons.OK, MessageBoxIcon.Information); } private async Task Message3() { await (new MessageBox(Modal)).Show("完了", $"〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇が完了しました。", "詳細は・・・・・・・・・・・\r\n・・・・・・・・・・・\r\n・・・・・・・・・・・\r\n", MessageBoxButtons.OK, MessageBoxIcon.Information); } private async Task Message4() { await (new MessageBox(Modal)).Show("警告", $"〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇が完了しました。", MessageBoxButtons.OK, MessageBoxIcon.Warning); } private async Task Message5() { await (new MessageBox(Modal)).Show("エラー", $"〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇〇が完了しました。", MessageBoxButtons.OK, MessageBoxIcon.Error); } } |
Visual Studio プロジェクト
今回使った Visual Studio プロジェクト テンプレートは、Blazor Server 5.0 の認証無し、HTTPS無しです。
コメント