new sample: update basemap for contrast changes#1813
Conversation
add accessibility category
add to featured samples exclude sample from sample sync
There was a problem hiding this comment.
Pull request overview
Adds a new Accessibility sample (“Update basemap for contrast accessibility”) across WPF, WinUI, and MAUI, and wires the new category into the shared featured-samples list and MAUI’s flyout menu.
Changes:
- Introduces a new cross-platform sample that switches between light/dark/high-contrast basemaps and optionally toggles reference layers.
- Adds a new “Accessibility” featured category and a corresponding MAUI flyout icon mapping.
- Updates the readme-copy tooling exclusions to avoid overwriting platform-specific readmes for this sample.
Reviewed changes
Copilot reviewed 15 out of 18 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| tools/readme_copy/readme_copy.py | Excludes the new sample from automated readme copying for MAUI/WinUI. |
| src/WPF/WPF.Viewer/Samples/Accessibility/UpdateBasemapForContrastAccessibility/UpdateBasemapForContrastAccessibility.xaml.cs | WPF implementation of the basemap/contrast switching logic and OS appearance listeners. |
| src/WPF/WPF.Viewer/Samples/Accessibility/UpdateBasemapForContrastAccessibility/UpdateBasemapForContrastAccessibility.xaml | WPF UI for contrast mode selection and reference layer toggle. |
| src/WPF/WPF.Viewer/Samples/Accessibility/UpdateBasemapForContrastAccessibility/readme.metadata.json | WPF sample metadata for docs/catalog. |
| src/WPF/WPF.Viewer/Samples/Accessibility/UpdateBasemapForContrastAccessibility/readme.md | WPF sample documentation. |
| src/WinUI/ArcGIS.WinUI.Viewer/Samples/Accessibility/UpdateBasemapForContrastAccessibility/UpdateBasemapForContrastAccessibility.xaml.cs | WinUI implementation of basemap switching + ThemeSettings handling. |
| src/WinUI/ArcGIS.WinUI.Viewer/Samples/Accessibility/UpdateBasemapForContrastAccessibility/UpdateBasemapForContrastAccessibility.xaml | WinUI UI for contrast mode selection and reference layer toggle. |
| src/WinUI/ArcGIS.WinUI.Viewer/Samples/Accessibility/UpdateBasemapForContrastAccessibility/readme.metadata.json | WinUI sample metadata for docs/catalog. |
| src/WinUI/ArcGIS.WinUI.Viewer/Samples/Accessibility/UpdateBasemapForContrastAccessibility/readme.md | WinUI sample documentation. |
| src/Samples.Shared/Resources/FeaturedSamples.xml | Adds a new featured “Accessibility” category and the new sample entry. |
| src/MAUI/Maui.Samples/ViewModels/FlyoutMenuViewModel.cs | Adds an icon mapping for the new “Accessibility” category. |
| src/MAUI/Maui.Samples/Samples/Accessibility/UpdateBasemapForContrastAccessibility/UpdateBasemapForContrastAccessibility.xaml.cs | MAUI implementation with per-platform contrast/theme detection and basemap switching. |
| src/MAUI/Maui.Samples/Samples/Accessibility/UpdateBasemapForContrastAccessibility/UpdateBasemapForContrastAccessibility.xaml | MAUI UI for contrast mode selection, settings deep-links, and reference layer toggle. |
| src/MAUI/Maui.Samples/Samples/Accessibility/UpdateBasemapForContrastAccessibility/readme.metadata.json | MAUI sample metadata for docs/catalog. |
| src/MAUI/Maui.Samples/Samples/Accessibility/UpdateBasemapForContrastAccessibility/readme.md | MAUI sample documentation. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| // Skip if the same basemap is already applied. | ||
| if (_lastAppliedChoice == choice) | ||
| return; | ||
|
|
||
| // Remember the new choice so duplicate notifications skip the rebuild. | ||
| _lastAppliedChoice = choice; | ||
|
|
||
| // Build the new basemap (the high-contrast variants require a portal-item fetch). | ||
| Basemap basemap; | ||
| try | ||
| { | ||
| basemap = await CreateBasemapAsync(choice); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| Debug.WriteLine($"Basemap failed to load: {ex.Message}"); | ||
| return; | ||
| } | ||
|
|
||
| // Assign the loaded basemap and apply the current reference-layer toggle state. | ||
| MyMapView.Map.Basemap = basemap; | ||
| ApplyReferenceLayerVisibility(basemap); | ||
| } |
| // Skip if the same basemap is already applied. | ||
| if (_lastAppliedChoice == choice) return; | ||
| _lastAppliedChoice = choice; | ||
|
|
||
| // Build the new basemap. | ||
| Basemap basemap; | ||
| try | ||
| { | ||
| basemap = await CreateBasemapAsync(choice); | ||
| } | ||
| catch (Exception ex) | ||
| { | ||
| System.Diagnostics.Debug.WriteLine($"Basemap failed to load: {ex.Message}"); | ||
| return; | ||
| } | ||
|
|
||
| // Assign the basemap and refresh reference-layer visibility. | ||
| MyMapView.Map.Basemap = basemap; | ||
| ApplyReferenceLayerVisibility(basemap); | ||
| } |
| // Track whether the OS appearance event handlers are currently subscribed. | ||
| private bool _eventsSubscribed; | ||
|
|
| // Resolve the basemap choice from the current mode and Windows appearance. | ||
| BasemapChoice choice = ResolveBasemapChoice(); | ||
|
|
||
| // Skip rebuilding if the same basemap is already applied. | ||
| if (_lastAppliedChoice == choice) | ||
| return; | ||
|
|
||
| // Capture the current viewpoint so the new map opens at the same location. | ||
| Viewpoint currentViewpoint = | ||
| MyMapView.GetCurrentViewpoint(ViewpointType.CenterAndScale) | ||
| ?? new Viewpoint(34.05, -117.19, 2e6); | ||
|
|
||
| // Build the new map with the captured viewpoint pre-seeded. | ||
| Map newMap = await CreateMapAsync(choice, currentViewpoint); | ||
|
|
||
| // Swap the new map into the MapView. Bail out if the swap was cancelled. | ||
| if (!await SwapMapAsync(newMap)) | ||
| return; | ||
|
|
||
| // Remember the applied choice and refresh reference layer visibility. | ||
| _lastAppliedChoice = choice; | ||
| ApplyReferenceLayerVisibility(newMap.Basemap); |
| // Build the map from the portal item and load it. | ||
| Map map = new Map(portalItem); | ||
| await map.LoadAsync(); | ||
| return map; |
imalcolm1
left a comment
There was a problem hiding this comment.
A couple of things but otherwise looks really good!
There was a problem hiding this comment.
WPF sometimes gets into a bad state when switching between high contrast themes. The map never loads and only shows the background grid until clicking the manual toggle and back.
| private void ApplyReferenceLayerVisibility(Basemap basemap) | ||
| { | ||
| // Skip if the basemap has no reference layers. | ||
| if (basemap?.ReferenceLayers == null) return; | ||
|
|
||
| // Read the desired visibility from the switch. | ||
| bool visible = ReferenceLayersSwitch.IsToggled; | ||
|
|
||
| // Set each reference layer to that visibility. | ||
| foreach (var layer in basemap.ReferenceLayers) | ||
| { | ||
| layer.IsVisible = visible; | ||
| } | ||
| } |
There was a problem hiding this comment.
There's an issue here (and on WPF and WinUI) where if ToggleReference layers is off and you switch between basemaps or between manual and automatic mode the layers will sometimes still show, particularly on the default basemaps. The fix seems to be to load the basemap before updating the layer visibility, which could either go here or somewhere in UpdateBasemapAsync
| private void ApplyReferenceLayerVisibility(Basemap basemap) | |
| { | |
| // Skip if the basemap has no reference layers. | |
| if (basemap?.ReferenceLayers == null) return; | |
| // Read the desired visibility from the switch. | |
| bool visible = ReferenceLayersSwitch.IsToggled; | |
| // Set each reference layer to that visibility. | |
| foreach (var layer in basemap.ReferenceLayers) | |
| { | |
| layer.IsVisible = visible; | |
| } | |
| } | |
| private async Task ApplyReferenceLayerVisibility(Basemap basemap) | |
| { | |
| // Skip if the basemap has no reference layers. | |
| if (basemap?.ReferenceLayers == null) return; | |
| // Read the desired visibility from the switch. | |
| bool visible = ReferenceLayersSwitch.IsToggled; | |
| // Ensure the basemap is loaded | |
| await basemap.LoadAsync(); | |
| // Set each reference layer to that visibility. | |
| foreach (var layer in basemap.ReferenceLayers) | |
| { | |
| layer.IsVisible = visible; | |
| } | |
| } |
There was a problem hiding this comment.
After clicking either of the open settings buttons on android, the app subsequently takes me to the same page no matter which one I click afterwards. This could be an android/samsung bug. Also, for the contrast settings link it navigates to general accessibility settings rather than the specific contrast settings page, but that one does seem like an android limitation.
|
|
||
| // Windows theme or high-contrast changed. ThemeSettings.Changed fires on the UI thread | ||
| // and covers both theme and high-contrast transitions. | ||
| private void OnThemeSettingsChanged(ThemeSettings sender, object args) |
There was a problem hiding this comment.
This doesn't seem to trigger when I switch light/dark theme. It works fine for high contrast though
Description
New Sample: Update basemap for contrast changes in the new Accessibility category
Type of change
Platforms tested on
Checklist