はじめに
ASP.NET は、Microsoft 社が提供する Web アプリケーション開発のフレームワークです。
アコーディオン機能とは複数のコンテンツをコンパクトにまとめ、
ユーザーが必要な情報をクリックして展開できるようにするインタラクティブなUI要素です。
モーダル機能とはユーザーが特定のアクションを行ったときに表示されるポップアップウィンドウです。
通常、ページ全体が背景を暗くしてモーダルの内容に焦点を合わせるために使われます。
①プロジェクトの作成
1.1 Visual Studio インストーラでのセットアップ
1. Visual Studio Installerを開き、次のワークロードを選択します:
・「ASP.NETとWeb開発」
説明:ASP.NET のアプリケーション開発に必要な機能やツールを提供します。
・「.NETデスクトップ開発」
説明:デスクトップアプリケーションと連携する場合に必要なツールを提供します。Windows FormsやWPFなど、デスクトップベースのアプリケーション開発を行う際に便利です。
2. 個別のコンポーネントとして、次のものを選択
・「.NET Framework 4.7.2 SDK」
説明:.NET Framework 4.7.2での開発を行うために必要なソフトウェア開発キット (SDK) です。このバージョンのフレームワークでアプリケーションを構築・コンパイルするために必要です。
・「.NET Framework 4.7.2 Targeting Pack」
説明:ASP.NET MVCプロジェクト (.NET Framework) をターゲットとするための必須コンポーネントです。ターゲティングパックをインストールすることで、特定のバージョンの.NET Frameworkでアプリケーションをビルドできます。
・「Entity Framework 6 Tools」
説明:データベースの操作を簡単に行えるツールセットです。Entity Frameworkを使用してデータベースへのCRUD(作成、読み取り、更新、削除)操作を行う際に便利で、モデルを自動生成する機能などが含まれます。
・「IIS Express」
説明:Webアプリケーションをローカルで実行し、テストするための軽量なWebサーバーです。Visual Studioに統合されており、デバッグや開発中のアプリケーションをローカル環境でホストするのに役立ちます。
1.2 Visual Studio で プロジェクトの作成
1. Visual Studioを起動し、プロジェクト作成
・「新しいプロジェクトの作成」をクリックします。
2. プロジェクトのテンプレートを選択
・ファイル → 新規作成 → プロジェクト から「新しいプロジェクト」を選択する。
・「ASP.NET Webアプリケーション (.NET Framework) 」を選択する。
・プロジェクト名を「ArticleDetails」に設定します。
・フレームワーク に「.NET Framework 4.7.2」を選択する。
・テンプレートの選択で「MVC」を選択し、「認証なし」を選択します。
②プロジェクトの構成
ArticleListApp/
│
├── Web.config (アプリケーション設定ファイル)
│ ※ルーティングやデータベース接続文字列の設定が記述。
│
├── Global.asax (アプリケーション全体のイベント管理)
│ ※アプリケーションのライフサイクルイベントやルーティングの設定を定義。
│
├── App_Start/
│ ├── RouteConfig.cs (ルーティング設定)
│ ├── FilterConfig.cs (フィルター設定)
│ └── BundleConfig.cs (JavaScriptとCSSのバンドル設定)
│
├── Models/
│ ├── Article.cs (記事データモデル)
│ └── ApplicationDbContext.cs (アプリケーションデータベースコンテキスト)
│
├── Controllers/
│ ├── HomeController.cs (ホームコントローラー)
│ ├── ArticleController.cs (記事管理用コントローラー)
│ └── ConfirmDeleteController.cs (記事削除確認コントローラー)
│
├── Views/
├── Shared/
│ └── _Layout.cshtml (共通レイアウトビュー)
│
└── Article/
├── Index.cshtml (記事一覧ページ)
├── Create.cshtml (記事作成ページ)
├── Details.cshtml (記事詳細ページ)
├── Edit.cshtml (記事編集ページ)
├── Delete.cshtml (記事削除ページ)
└── ConfirmDelete.cshtml (記事削除確認モーダル)
③ルーティング設定
・Global.asaxファイルに定義されたルートテーブルにより、コントローラーとアクションメソッドへのマッピングが行われます。
・デフォルト設定でのルートテーブルは、URLの最初の部分をコントローラー、2番目をアクション、3番目をオプションのidパラメーターとして解釈します。
・ Application_Start()メソッドでRegisterRoutesメソッドが呼ばれ、ルート設定が初期化されます。
以下の内容を Web.config に追加して、プロジェクトの設定を完了させます。
・・・
<configuration>
・・・
<!--
web.config ファイルに dotless セクションを追加。
-->
<section name="dotless" type="dotless.Core.DotlessConfiguration, dotless" />
</configSections>
・・・
</system.web>
<!--
<modules runAllManagedModulesForAllRequests="true" />:
ASP.NET のすべてのモジュールを、
静的ファイル(CSS, JS, 画像ファイルなど)も含めた
すべてのリクエストに対して実行するように設定します。
その他上記の設定により、アプリケーション内の
すべてのリクエストに対して「404 Not Found」を返すように設定されます。
-->
<system.webServer>
<modules runAllManagedModulesForAllRequests="true"/>
<handlers>
<remove name="ExtensionlessUrlHandler-Integrated-4.0" />
<add name="ExtensionlessUrlHandler-Integrated-4.0" path="*" verb="*" type="System.Web.HttpNotFoundHandler" resourceType="Unspecified" preCondition="integratedMode,runtimeVersionv4.0"/>
</handlers>
</system.webServer>
・・・
・・・
</system.codedom>
<!--
dotless をWebモードで使用する場合は、
web="false" を web="true" に変更してください。
-->
<dotless minifyCss="false" cache="true" web="true" strictMath="false" />
・・・
④必要なパッケージのインストール
NuGet パッケージの管理を開きます:
Visual Studio の「ソリューション エクスプローラー」でプロジェクト
(ArticleDetails)を右クリックし、
「NuGet パッケージの管理」を選択します。
「参照」タブで NuGet パッケージをインストール
・ EntityFramework - データベースコンテキストクラス の主要ライブラリ
・ Microsoft.Web.Pages - ASP.NET Web Pages を利用するためのライブラリ
・ dotless - LESS CSS ファイルをコンパイルしてブラウザに提供するためのライブラリ
・ Microsoft.AspNet.Mvc - ASP.NET MVC の主要ライブラリ
・ Newtonsoft.Json - JSON 処理用ライブラリ
・ System.Web.Optimization - リソースの最適化用ライブラリインストールすると、Web.config にバインドリダイレクトの設定が自動的に追加されます
⑤アプリケーションのライフサイクル管理の設定
5.1 Global.asax
・アプリケーション全体のライフサイクルイベント(アプリケーションの開始や終了など)を管理します。
・Global.asax.cs の Application_Start メソッドで、ルーティングやバンドル設定を行います。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
namespace ArticleDetails // ここが名前空間
{
public class MvcApplication : System.Web.HttpApplication
{
protected void Application_Start()
{
// アプリケーション内のすべてのエリアの登録
AreaRegistration.RegisterAllAreas();
// グローバルフィルタをすべてのコントローラに設定
FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
// ルート設定の初期化
RouteConfig.RegisterRoutes(RouteTable.Routes);
// スクリプトやスタイルのバンドル設定
BundleConfig.RegisterBundles(BundleTable.Bundles);
}
}
}
5.2 RouteConfig.cs
・RouteConfig.cs: ルーティングの設定を管理。アプリのURLに基づいてどのコントローラーとアクションを呼び出すかを定義します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;
namespace ArticleDetails
{
public class RouteConfig
{
public static void RegisterRoutes(RouteCollection routes)
{
/* IgnoreRouteメソッドで、.axdリソースにアクセスするURLを除外 */
routes.IgnoreRoute("{resource}.axd/{*pathInfo}");
/* MapRouteメソッドで、デフォルトのコントローラーをArticleControllerに設定
アクションはIndex、idは省略可能 */
routes.MapRoute(
name: "Default",
url: "{controller}/{action}/{id}",
defaults: new { controller = "Article", action = "Index", id = UrlParameter.Optional }
);
}
}
}
5.3 IIS をインストール
Windows の「コントロールパネル」を開きます。
スタートメニューを開いて、「コントロールパネル」を検索し、選択します。
「プログラムと機能」を選択します。
左側の「Windows の機能の有効化または無効化」をクリックします。
これにより「Windows の機能」ウィンドウが開きます。
「インターネット インフォメーション サービス (IIS)」を探し、
チェックボックスをオンにします。
必要な機能を選択することができます。
デフォルトでは「Web 管理ツール」や
「World Wide Web サービス」などの基本的な IIS 機能が含まれます。
「OK」をクリックして、インストールを完了させます。
⑥モデルの作成
6.1 Models フォルダにクラス Article.cs を追加
Modelsフォルダーを右クリックし、「追加」→「クラス」を選択し、"Article.cs"を追加します。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
namespace ArticleDetails.Models
{
public class Article
{
// プライマリキー
public int Id { get; set; }
// 記事のタイトルを表すプロパティ
public string Title { get; set; }
// 記事の本文や内容を格納するプロパティ
public string Content { get; set; }
// 記事が公開された日付と時刻を格納するプロパティ
public DateTime PublishDate { get; set; }
}
}
6.2 Models フォルダにデータベースコンテキストのクラス ApplicationDbContext.cs を追加
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Data.Entity;
using ArticleDetails.Models;
namespace ArticleDetails.Models
{
public class ApplicationDbContext : DbContext
{
// "DefaultConnection" という名前の接続文字列を使用
public ApplicationDbContext() : base("DefaultConnection") { }
// Articles テーブルに対応する DbSet
public DbSet<Article> Articles { get; set; }
}
}
⑦コントローラーの作成
Controllers フォルダにある HomeController.cs をコピーし、新しい記事 (Article) のデータを操作するためのコントローラー ArticleController.cs を作成します。
7.1 HomeController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace ArticleDetails.Controllers
{
public class HomeController : Controller
{
/* Index メソッドは、View() メソッドを呼び出し、
対応する Index ビュー(Views/Home/Index.cshtml)を返します。 */
public ActionResult Index()
{
return View();
}
}
}
7.2 ArticleController.cs
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Mvc;
using ArticleDetails.Models;
namespace ArticleDetails.Controllers
{
public class ArticleController : Controller
{
/* _context という ApplicationDbContext インスタンスが作成され、
データベースと接続します。
このインスタンスは、記事データへのアクセスに使われます。 */
private ApplicationDbContext _context = new ApplicationDbContext();
// 一覧表示
public ActionResult Index()
{
/* _context.Articles.ToList() によって
全記事データ(articles)を取得し、Index ビューに渡します。 */
var articles = _context.Articles.ToList();
return View(articles);
}
// 詳細表示
public ActionResult Details(int id)
{
var article = _context.Articles.Find(id);
/* Find メソッドで記事(article)を取得
見つからない場合は HttpNotFound() を返します。 */
if (article == null) return HttpNotFound();
/* 見つかった場合は 記事(article)を Details ビューに渡します。 */
return View(article);
}
// 新規作成フォーム(GET)
public ActionResult Create()
{
/* 空のフォームを Create ビューに表示します。 */
return View();
}
// 新規作成の保存(POST)
/* HttpPost 属性が付いており、フォームから送信された記事データを処理します。 */
[HttpPost]
public ActionResult Create(Article article)
{
/* モデルの状態が有効(ModelState.IsValid) であれば、
記事をデータベースに追加し、
保存(SaveChanges()) した後、
Index ページにリダイレクトします。*/
if (ModelState.IsValid)
{
_context.Articles.Add(article);
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(article);
}
// 編集フォーム(GET)
public ActionResult Edit(int id)
{
/* 編集対象の id に対応する記事を取得
見つからない場合は HttpNotFound() を返します。 */
var article = _context.Articles.Find(id);
if (article == null) return HttpNotFound();
/* 見つかった場合は 編集フォームを表示する。 */
return View(article);
}
// 編集の保存(POST)
[HttpPost]
public ActionResult Edit(Article article)
{
/* 編集フォームから送信されたデータを処理し、
ModelState.IsValid が true であれば
データベース内の記事を更新します。 */
if (ModelState.IsValid)
{
/* EntityState.Modified を使用して、
エンティティの状態を「修正済み」に設定し、
SaveChanges() メソッドで変更を保存します。 */
_context.Entry(article).State = EntityState.Modified;
_context.SaveChanges();
return RedirectToAction("Index");
}
return View(article);
}
// 記事を削除する
public ActionResult Delete(int id)
{
var article = _context.Articles.SingleOrDefault(a => a.Id == id);
if (article == null)
{
return HttpNotFound();
}
return View(article);
}
// 記事を削除する(POST)
[HttpPost, ActionName("Delete")]
public ActionResult DeleteConfirmed(int id)
{
var article = _context.Articles.SingleOrDefault(a => a.Id == id);
if (article == null)
{
return HttpNotFound();
}
_context.Articles.Remove(article); // 記事を削除
_context.SaveChanges(); // データベースに変更を反映
return RedirectToAction("Index"); // 一覧ページにリダイレクト
}
}
}
7.3 ConfirmDeleteController.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using ArticleDetails.Models;
namespace ArticleDetails.Controllers
{
public class ConfirmDeleteController : Controller
{
private ApplicationDbContext _context = new ApplicationDbContext();
// 削除確認を表示するアクション
public ActionResult Confirm(int id)
{
var article = _context.Articles.Find(id);
if (article == null)
return HttpNotFound();
return View("ConfirmDelete", article);
}
// 削除処理を行うアクション
[HttpPost]
public ActionResult Delete(int id)
{
var article = _context.Articles.Find(id);
if (article == null)
return HttpNotFound();
_context.Articles.Remove(article);
_context.SaveChanges();
return RedirectToAction("Index", "Article");
}
}
}
⑧ビューの作成
Views 配下の Shared フォルダにある
以下のビューを修正します。
8.1 _Layout.cshtml
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<!-- ページタイトルを設定。ViewBag.Titleが空なら、"ArticleDetails"がタイトルに表示されます -->
<title>@ViewBag.Title - ArticleDetails</title>
<!-- 外部CSSファイルをリンク。サイト全体のスタイルを管理 -->
<link rel="stylesheet" href="~/Content/Site.css" />
<!-- Web開発を容易にするためのフレームワークである Bootstrap の CSS ファイル -->
<link href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" rel="stylesheet">
</head>
<body>
<header>
<h1>ArticleDetails</h1>
<nav>
<!-- ホームページへのリンク。HomeコントローラーのIndexアクションへ -->
@Html.ActionLink("Home", "Index", "Home") |
<!-- 記事一覧ページへのリンク。ArticleコントローラーのIndexアクションへ -->
@Html.ActionLink("Articles", "Index", "Article")
</nav>
</header>
<!-- 各ビューの内容がここにレンダリングされます -->
<div class="container">
@RenderBody()
</div>
<!-- 現在の年を表示し、コピーライトを表示 -->
<footer>
<p>© @DateTime.Now.Year - ArticleDetails</p>
</footer>
</body>
</html>
Views 配下に Article フォルダを作成し、
以下のビューを作成します。
8.2 Index.cshtml
<!-- このビューはArticleモデルのリストをJavaScriptのアコーディオンで表示します -->
@model IEnumerable<ArticleDetails.Models.Article>
<h2>Articles</h2>
<!-- "新しい記事を作成"のリンクを表示し、"Create"アクションを呼び出します -->
<p>
@Html.ActionLink("Create New Article", "Create")
</p>
<!-- アコーディオンのタイトル部分 -->
<div class="accordion-header" onclick="toggleAccordion()">
<h2>Data(クリックでデータの表示・非表示を切り替える)</h2>
</div>
<!-- アコーディオンの内容部分(初期状態では非表示)-->
<div class="accordion-content" id="accordionContent" style="display:none;">
<!-- 記事の情報をテーブルで表示 -->
<table class="table">
<thead>
<tr>
<!-- 記事のタイトル列 -->
<th>Title</th>
<!-- 記事の公開日列 -->
<th>Publish Date</th>
<!-- アクション列(詳細、編集、削除のリンク) -->
<th></th>
</tr>
</thead>
<tbody>
<!-- ModelはIEnumerable<Article>のリストです -->
@foreach (var article in Model)
{
<tr>
<!-- 記事のタイトル列 -->
<td>@article.Title</td>
<!-- 記事の公開日列 -->
<td>@article.PublishDate.ToShortDateString()</td>
<!-- アクション列(詳細、編集、削除のリンク) -->
<td>
@Html.ActionLink("Details", "Details", new { id = article.Id }) |
@Html.ActionLink("Edit", "Edit", new { id = article.Id }) |
<!-- 削除リンク(Deleteページへ遷移) -->
<a href="@Url.Action("Delete", "Article", new { id = article.Id })" class="btn btn-danger">Delete</a>
</td>
</tr>
}
</tbody>
</table>
</div>
<script>
// アコーディオンメニューの開閉機能
function toggleAccordion() {
// アコーディオンの内容部分を取得
const content = document.getElementById('accordionContent');
if (content.style.display === "none" || content.style.display === "") {
// 表示されていない場合は表示
content.style.display = "block";
} else {
// 表示されている場合は非表示
content.style.display = "none";
}
}
</script>
・アコーディオンのタイトル部分 (accordion-header) をクリックすると、toggleAccordion() 関数が呼ばれ、対応するコンテンツ (accordion-content) の表示・非表示が切り替わります。
8.3 Create.cshtml
<!-- このビューはArticleモデルの新規データ入力箇所をアコーディオンで表示します。 -->
@model ArticleDetails.Models.Article
<!-- アコーディオン本体の開始 -->
<div class="accordion my-3" id="accordionExample">
<div class="accordion-item">
<h2 class="accordion-header" id="headingOne">
<!-- アコーディオンボタン(クリックでデータ入力フォームが表示される)-->
<!-- "collapsed"クラスが付与されており、初期状態で非表示になっています -->
<button class="accordion-button collapsed" type="button">
Create New Article(クリックで表示・非表示を切り替える)
</button>
</h2>
<!-- アコーディオンの内容部分 -->
<!-- "collapse"クラスはアコーディオンが初期状態で非表示であることを意味します -->
<div class="accordion-collapse collapse" id="collapseOne">
<div class="accordion-body">
<!-- 記事作成フォームの開始
フォーム送信時にCreateアクションを呼び出して記事を作成します -->
@using (Html.BeginForm())
{
<div class="mb-3">
<!-- 記事のタイトル入力欄 -->
<label class="form-label">Title</label>
@Html.TextBoxFor(m => m.Title, new { @class = "form-control" })
</div>
<div class="mb-3">
<!-- 記事の内容入力欄 -->
<label class="form-label">Content</label>
@Html.TextAreaFor(m => m.Content, new { @class = "form-control" })
</div>
<div class="mb-3">
<!-- 記事の公開日入力欄(日時形式) -->
<label class="form-label">Publish Date</label>
@Html.TextBoxFor(m => m.PublishDate, "{0:yyyy-MM-dd}", new { @class = "form-control", type = "date" })
</div>
<!-- 新しい記事の作成を実行するボタン -->
<button type="submit" class="btn btn-primary">Create</button>
}
</div>
</div>
</div>
</div>
<!-- 記事一覧ページに戻るリンク -->
<p>
@Html.ActionLink("Back to List", "Index")
</p>
<!-- jQueryライブラリの読み込み -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
// ドキュメントが準備できたら実行される
$(document).ready(function () {
// アコーディオンボタンがクリックされた時の処理
$('.accordion-button').click(function () {
// クリックされたアコーディオンボタンに対応するアコーディオン内容部分を取得
const content = $(this).closest('.accordion-item').find('.accordion-collapse');
/* thisは、クリックイベントが発生したボタン(accordion-button)を指します。 */
/* .closest('.accordion-item')は、クリックされたボタンが属する最も近い .accordion-item を取得します。 */
/* .find('.accordion-collapse') は、上記で取得したものから、.accordion-collapse 要素(アコーディオンの内容部分)を探して取得します。*/
// 他のアコーディオンの内容部分を閉じる
$('.accordion-collapse').not(content).slideUp().removeClass('show');
// 対象アコーディオンの表示/非表示を切り替え
content.slideToggle().toggleClass('show');
/* slideToggle() は、対象要素の表示/非表示をスライド効果を使って切り替えます。 */
// 他のアコーディオンボタンが閉じられるように、"collapsed"クラスを適用
$('.accordion-button').not(this).addClass('collapsed');
// クリックされたボタンの状態に応じて"collapsed"クラスを切り替え
$(this).toggleClass('collapsed', !content.hasClass('show'));
/* .toggleClass('show') は、対象要素に show クラスを付けたり外したりすることで、アコーディオンの開閉状態を視覚的に変更します。*/
});
});
</script>
8.4 Details.cshtml
<!-- このビューはArticleモデルを表示します。 -->
@model ArticleDetails.Models.Article
<h2>Details</h2>
<div>
<!-- 記事のタイトル -->
<h3>@Model.Title</h3>
<!-- 記事の内容 -->
<p>@Model.Content</p>
<!-- 記事の公開日 -->
<p><strong>Publish Date:</strong> @Model.PublishDate.ToShortDateString()</p>
</div>
<!-- 編集リンクと一覧ページへのリンク -->
<p>
@Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
@Html.ActionLink("Back to List", "Index")
</p>
8.5 Edit.cshtml
<!-- このビューはArticleモデルをJavaScriptのポップアップで確認して削除します。 -->
@model ArticleDetails.Models.Article
<h2>Edit Article</h2>
@using (Html.BeginForm())
{
@Html.HiddenFor(m => m.Id)
<!-- 記事のタイトル入力フィールド -->
<div>
<label>Title</label>
@Html.TextBoxFor(m => m.Title)
</div>
<!-- 記事の内容入力フィールド -->
<div>
<label>Content</label>
@Html.TextAreaFor(m => m.Content)
</div>
<!-- 記事の公開日入力フィールド -->
<div>
<label>Publish Date</label>
@Html.TextBoxFor(m => m.PublishDate, "{0:yyyy-MM-dd}", new { type = "date" })
</div>
<!-- 保存ボタン -->
<button type="submit" onclick="return confirmSave()">Save</button>
}
<p>
@Html.ActionLink("Back to List", "Index")
</p>
<!-- JavaScript: 保存確認ポップアップを表示する -->
<script type="text/javascript">
function confirmSave() {
// ユーザーに確認ダイアログを表示
var result = confirm("既存のデータが上書きされます、よろしいですか?");
// OKが押された場合のみフォームを送信
return result;
}
</script>
8.6 Delete.cshtml
<!-- このビューはArticleモデルをBootstrapのモーダルで確認して削除します。 -->
@model ArticleDetails.Models.Article
<!-- jQueryライブラリの読み込み -->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<!-- Bootstrap JavaScriptの読み込み -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha1/dist/js/bootstrap.bundle.min.js"></script>
<h2>Delete Article</h2>
<!-- 記事詳細 -->
<div>
<h3>Are you sure you want to delete this article?</h3>
<div>
<label>Title:</label>
<p>@Model.Title</p>
</div>
<div>
<label>Content:</label>
<p>@Model.Content</p>
</div>
<div>
<label>Publish Date:</label>
<p>@Model.PublishDate.ToShortDateString()</p>
</div>
</div>
<!-- 削除ボタン。クリックするとモーダルが表示される -->
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#confirmDeleteModal">
Delete
</button>
<!-- モーダルの開始 -->
<div class="modal fade" id="confirmDeleteModal" tabindex="-1" aria-labelledby="confirmDeleteModalLabel" aria-hidden="true">
<!-- モーダルダイアログ -->
<div class="modal-dialog">
<!-- モーダルコンテンツ -->
<div class="modal-content">
<!-- モーダルヘッダー -->
<div class="modal-header">
<!-- モーダルタイトル -->
<h5 class="modal-title" id="confirmDeleteModalLabel">Confirm Deletion</h5>
<!-- モーダルを閉じるボタン -->
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<!-- モーダルボディ -->
<div class="modal-body">
<p>Are you sure you want to delete the article titled "<strong>@Model.Title</strong>"?</p>
</div>
<!-- モーダルフッター -->
<div class="modal-footer">
<!-- モーダルを閉じるボタン -->
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<!-- 削除フォーム -->
@using (Html.BeginForm("Delete", "Article", new { id = Model.Id }, FormMethod.Post))
{
<!-- 削除ボタン -->
<button type="submit" class="btn btn-danger">Delete</button>
}
</div>
</div>
</div>
</div>
<p>
@Html.ActionLink("Back to List", "Index")
</p>