// XAML Map Control - https://github.com/ClemensFischer/XAML-Map-Control // Copyright © 2024 Clemens Fischer // Licensed under the Microsoft Public License (Ms-PL) using System; #if WINUI using Windows.Foundation; using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Data; #elif UWP using Windows.Foundation; using Windows.UI.Xaml; using Windows.UI.Xaml.Controls; using Windows.UI.Xaml.Data; #else using System.Windows; using System.Windows.Controls; using System.Windows.Data; #endif namespace MapControl { /// /// Manages a collection of selectable items on a Map. /// public partial class MapItemsControl : ListBox { public static readonly DependencyProperty LocationMemberPathProperty = DependencyProperty.Register( nameof(LocationMemberPath), typeof(string), typeof(MapItemsControl), new PropertyMetadata(null)); /// /// Path to a source property for binding the Location property of MapItem containers. /// public string LocationMemberPath { get => (string)GetValue(LocationMemberPathProperty); set => SetValue(LocationMemberPathProperty, value); } protected override DependencyObject GetContainerForItemOverride() { return new MapItem(); } protected override bool IsItemItsOwnContainerOverride(object item) { return item is MapItem; } protected override void PrepareContainerForItemOverride(DependencyObject element, object item) { base.PrepareContainerForItemOverride(element, item); if (LocationMemberPath != null && element is MapItem mapItem) { mapItem.SetBinding(MapItem.LocationProperty, new Binding { Path = new PropertyPath(LocationMemberPath), Source = item }); } } protected override void ClearContainerForItemOverride(DependencyObject element, object item) { base.ClearContainerForItemOverride(element, item); if (LocationMemberPath != null && element is MapItem mapItem) { mapItem.ClearValue(MapItem.LocationProperty); } } public void SelectItems(Predicate predicate) { if (SelectionMode == SelectionMode.Single) { throw new InvalidOperationException("SelectionMode must not be Single"); } foreach (var item in Items) { var selected = predicate(item); if (selected != SelectedItems.Contains(item)) { if (selected) { SelectedItems.Add(item); } else { SelectedItems.Remove(item); } } } } public void SelectItemsByLocation(Predicate predicate) { SelectItems(item => { var loc = MapPanel.GetLocation(ContainerFromItem(item)); return loc != null && predicate(loc); }); } public void SelectItemsByPosition(Predicate predicate) { SelectItems(item => { var pos = MapPanel.GetViewPosition(ContainerFromItem(item)); return pos.HasValue && predicate(pos.Value); }); } public void SelectItemsInRect(Rect rect) { SelectItemsByPosition(p => rect.Contains(p)); } protected internal void OnItemClicked(FrameworkElement mapItem, bool controlKey, bool shiftKey) { var item = ItemFromContainer(mapItem); if (SelectionMode == SelectionMode.Single) { // Single -> set only SelectedItem. if (SelectedItem != item) { SelectedItem = item; } else if (controlKey) { SelectedItem = null; } } else if (SelectionMode == SelectionMode.Multiple || controlKey) { // Multiple or Extended with Ctrl -> toggle item in SelectedItems. if (SelectedItems.Contains(item)) { SelectedItems.Remove(item); } else { SelectedItems.Add(item); } } else if (shiftKey && SelectedItem != null) { // Extended with Shift -> select items in view rectangle. var p1 = MapPanel.GetViewPosition(ContainerFromItem(SelectedItem)); var p2 = MapPanel.GetViewPosition(mapItem); if (p1.HasValue && p2.HasValue) { SelectItemsInRect(new Rect(p1.Value, p2.Value)); } } else if (SelectedItem != item) { // Extended without Control or Shift -> set selected item. SelectedItem = item; } } } }