最新記事=> 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無しです。


 
  
  
  
  

コメント