navigationRegions = new()
+ {
+ new RectangleHotSpot
+ {
+ Left = 20, Top = 50, Right = 180, Bottom = 120,
+ AlternateText = "Home Page",
+ NavigateUrl = "/"
+ },
+ new RectangleHotSpot
+ {
+ Left = 200, Top = 50, Right = 360, Bottom = 120,
+ AlternateText = "Products",
+ NavigateUrl = "/products"
+ },
+ new RectangleHotSpot
+ {
+ Left = 380, Top = 50, Right = 540, Bottom = 120,
+ AlternateText = "Contact Us",
+ NavigateUrl = "/contact"
+ }
+ };
+}
+```
+
+### Interactive Diagram with PostBack
+
+```razor
+@page "/floor-plan"
+
+Office Floor Plan
+Click on a room to see details
+
+
+
+@if (!string.IsNullOrEmpty(selectedRoom))
+{
+
+
@selectedRoom
+
@roomDetails
+
+}
+
+@code {
+ private string selectedRoom = "";
+ private string roomDetails = "";
+
+ private List roomRegions = new()
+ {
+ new PolygonHotSpot
+ {
+ Coordinates = "50,50,150,50,150,150,50,150",
+ AlternateText = "Conference Room A",
+ PostBackValue = "ConfA"
+ },
+ new CircleHotSpot
+ {
+ X = 300, Y = 100, Radius = 40,
+ AlternateText = "Break Room",
+ PostBackValue = "Break"
+ }
+ };
+
+ private void ShowRoomDetails(ImageMapEventArgs e)
+ {
+ selectedRoom = e.PostBackValue switch
+ {
+ "ConfA" => "Conference Room A",
+ "Break" => "Break Room",
+ _ => "Unknown Room"
+ };
+
+ roomDetails = e.PostBackValue switch
+ {
+ "ConfA" => "Capacity: 12 people. Equipped with projector and whiteboard.",
+ "Break" => "Kitchen facilities, coffee maker, and seating for 8.",
+ _ => ""
+ };
+ }
+}
+```
+
+### Mixed Mode Map
+
+```razor
+
+
+@code {
+ private List mixedRegions = new()
+ {
+ // External link - opens in new window
+ new RectangleHotSpot
+ {
+ Left = 10, Top = 10, Right = 100, Bottom = 60,
+ AlternateText = "Documentation",
+ NavigateUrl = "https://docs.example.com",
+ Target = "_blank",
+ HotSpotMode = HotSpotMode.Navigate
+ },
+
+ // Server action - triggers event
+ new CircleHotSpot
+ {
+ X = 150, Y = 35, Radius = 25,
+ AlternateText = "Download",
+ PostBackValue = "StartDownload",
+ HotSpotMode = HotSpotMode.PostBack
+ },
+
+ // Inactive region - informational only
+ new PolygonHotSpot
+ {
+ Coordinates = "200,10,250,10,225,50",
+ AlternateText = "Coming Soon",
+ HotSpotMode = HotSpotMode.Inactive
+ }
+ };
+
+ private void HandleAction(ImageMapEventArgs e)
+ {
+ if (e.PostBackValue == "StartDownload")
+ {
+ // Initiate download logic
+ }
+ }
+}
+```
+
+## Migration Tips
+
+1. **Convert Declarative HotSpots to Collection**: In Web Forms, HotSpots are declared as child elements. In Blazor, create a List in your @code block.
+
+2. **Event Handler Signature**: Web Forms uses `ImageMapEventHandler` with sender and `ImageMapEventArgs`. Blazor simplifies this - you only need the `ImageMapEventArgs` parameter.
+
+3. **Coordinate Validation**: Consider validating HotSpot coordinates are within image bounds to prevent rendering issues.
+
+4. **Dynamic HotSpots**: In Blazor, you can easily add/remove HotSpots dynamically by modifying the List and calling `StateHasChanged()`.
+
+## See Also
+
+- [Image](Image.md) - Display static images
+- [ImageButton](ImageButton.md) - Clickable image that acts as a button
+- [HyperLink](HyperLink.md) - Text or image hyperlinks
diff --git a/mkdocs.yml b/mkdocs.yml
index fb0ac6c9..0c72ca45 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -72,6 +72,7 @@ nav:
- HiddenField: EditorControls/HiddenField.md
- Image: EditorControls/Image.md
- ImageButton: EditorControls/ImageButton.md
+ - ImageMap: EditorControls/ImageMap.md
- Label: EditorControls/Label.md
- LinkButton: EditorControls/LinkButton.md
- ListBox: EditorControls/ListBox.md
diff --git a/status.md b/status.md
index 208cd7dc..b5d55381 100644
--- a/status.md
+++ b/status.md
@@ -2,18 +2,18 @@
| Category | Completed | In Progress | Not Started | Total |
|----------|-----------|-------------|-------------|-------|
-| Editor Controls | 17 | 0 | 10 | 27 |
+| Editor Controls | 18 | 0 | 9 | 27 |
| Data Controls | 7 | 0 | 2 | 9 |
| Validation Controls | 7 | 0 | 0 | 7 |
| Navigation Controls | 3 | 0 | 0 | 3 |
| Login Controls | 4 | 0 | 3 | 7 |
-| **TOTAL** | **38** | **0** | **15** | **53** |
+| **TOTAL** | **39** | **0** | **14** | **53** |
---
## Detailed Component Breakdown
-### 🟡 Editor Controls (15/27 - 56% Complete)
+### 🟡 Editor Controls (18/27 - 67% Complete)
| Component | Status | Notes |
|-----------|--------|-------|
@@ -34,7 +34,7 @@
| Calendar | 🔴 Not Started | Complex date picker |
| CheckBoxList | ✅ Complete | Documented, tested (26 tests) |
| FileUpload | 🔴 Not Started | Consider Blazor InputFile |
-| ImageMap | 🔴 Not Started | Clickable image regions |
+| ImageMap | ✅ Complete | Documented, tested (23 tests) |
| ListBox | ✅ Complete | Documented, tested, supports single/multi-select |
| Localize | 🔴 Not Started | Localization control |
| MultiView | 🔴 Not Started | Tab container |
@@ -143,12 +143,12 @@
#### Lower Priority / Consider Deferring
| Component | Complexity | Notes |
|-----------|------------|-------|
-| **BulletedList** | Low | Simple HTML list |
+| ~~**BulletedList**~~ | ~~Low~~ | ~~Simple HTML list~~ | ✅ Complete |
| **Calendar** | High | Complex date picker |
| **FileUpload** | Medium | Blazor has InputFile |
-| **ImageMap** | Medium | Clickable regions |
+| ~~**ImageMap**~~ | ~~Medium~~ | ~~Clickable regions~~ | ✅ Complete |
| **MultiView/View** | Medium | Tab-like container |
-| **Table** | Low | HTML table wrapper |
+| ~~**Table**~~ | ~~Low~~ | ~~HTML table wrapper~~ | ✅ Complete |
| **Localize** | Low | Localization |
| **Xml** | Medium | XML transform |
| **Substitution** | N/A | Cache-related, may not apply |
From de0647ceeb55cb7a1b1142496b82b287e8a8a783 Mon Sep 17 00:00:00 2001
From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com>
Date: Mon, 9 Feb 2026 17:50:36 +0000
Subject: [PATCH 5/6] Fix code review issues: use unique counter for map IDs,
return Task from event handler, fix mode inheritance logic
Co-authored-by: csharpfritz <78577+csharpfritz@users.noreply.github.com>
---
src/BlazorWebFormsComponents/Enums/HotSpotMode.cs | 5 +++++
src/BlazorWebFormsComponents/HotSpot.cs | 2 +-
src/BlazorWebFormsComponents/ImageMap.razor | 2 +-
src/BlazorWebFormsComponents/ImageMap.razor.cs | 13 ++++++++-----
4 files changed, 15 insertions(+), 7 deletions(-)
diff --git a/src/BlazorWebFormsComponents/Enums/HotSpotMode.cs b/src/BlazorWebFormsComponents/Enums/HotSpotMode.cs
index c1b13c98..18570dbd 100644
--- a/src/BlazorWebFormsComponents/Enums/HotSpotMode.cs
+++ b/src/BlazorWebFormsComponents/Enums/HotSpotMode.cs
@@ -5,6 +5,11 @@ namespace BlazorWebFormsComponents.Enums
///
public enum HotSpotMode
{
+ ///
+ /// The HotSpot mode is not set and inherits from the parent ImageMap control.
+ ///
+ NotSet,
+
///
/// The HotSpot does not have any behavior.
///
diff --git a/src/BlazorWebFormsComponents/HotSpot.cs b/src/BlazorWebFormsComponents/HotSpot.cs
index e9fe5dcb..8ba745b1 100644
--- a/src/BlazorWebFormsComponents/HotSpot.cs
+++ b/src/BlazorWebFormsComponents/HotSpot.cs
@@ -15,7 +15,7 @@ public abstract class HotSpot
///
/// Gets or sets the behavior of a HotSpot object in an ImageMap control when the HotSpot is clicked.
///
- public HotSpotMode HotSpotMode { get; set; } = HotSpotMode.Navigate;
+ public HotSpotMode HotSpotMode { get; set; } = HotSpotMode.NotSet;
///
/// Gets or sets the URL to navigate to when a HotSpot object is clicked.
diff --git a/src/BlazorWebFormsComponents/ImageMap.razor b/src/BlazorWebFormsComponents/ImageMap.razor
index d0430a02..4839322e 100644
--- a/src/BlazorWebFormsComponents/ImageMap.razor
+++ b/src/BlazorWebFormsComponents/ImageMap.razor
@@ -14,7 +14,7 @@
- public partial class ImageMap : BaseWebFormsComponent, IImageComponent
+ public partial class ImageMap : BaseStyledComponent, IImageComponent
{
///
/// Gets or sets the alternate text to display in the ImageMap control when the image is unavailable.
@@ -71,14 +72,11 @@ public partial class ImageMap : BaseWebFormsComponent, IImageComponent
[Parameter]
public bool GenerateEmptyAlternateText { get; set; }
- private static int _mapIdCounter = 0;
- private string _mapId = string.Empty;
+ private readonly string _mapId = $"ImageMap_{Guid.NewGuid():N}";
protected override void OnInitialized()
{
base.OnInitialized();
- // Generate a unique map ID using a counter
- _mapId = $"ImageMap_{System.Threading.Interlocked.Increment(ref _mapIdCounter)}";
}
///