Support for standard SelectionModes Single, Multiple and Extended in MapItemsControl, made IsCurrent a read-only attached property in MapItemsControl, cleaned dependencies between MapItemsControl and MapItems.

This commit is contained in:
ClemensF 2012-08-22 20:21:31 +02:00
parent db1201ad47
commit 35c561d8aa
8 changed files with 222 additions and 158 deletions

View file

@ -464,29 +464,29 @@ namespace MapControl
}
}
private void TileLayerCollectionChanged(object sender, NotifyCollectionChangedEventArgs eventArgs)
private void TileLayerCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
switch (eventArgs.Action)
switch (e.Action)
{
case NotifyCollectionChangedAction.Add:
tileContainer.AddTileLayers(eventArgs.NewStartingIndex, eventArgs.NewItems.Cast<TileLayer>());
tileContainer.AddTileLayers(e.NewStartingIndex, e.NewItems.Cast<TileLayer>());
break;
case NotifyCollectionChangedAction.Remove:
tileContainer.RemoveTileLayers(eventArgs.OldStartingIndex, eventArgs.OldItems.Cast<TileLayer>());
tileContainer.RemoveTileLayers(e.OldStartingIndex, e.OldItems.Cast<TileLayer>());
break;
case NotifyCollectionChangedAction.Move:
case NotifyCollectionChangedAction.Replace:
tileContainer.RemoveTileLayers(eventArgs.OldStartingIndex, eventArgs.OldItems.Cast<TileLayer>());
tileContainer.AddTileLayers(eventArgs.NewStartingIndex, eventArgs.NewItems.Cast<TileLayer>());
tileContainer.RemoveTileLayers(e.OldStartingIndex, e.OldItems.Cast<TileLayer>());
tileContainer.AddTileLayers(e.NewStartingIndex, e.NewItems.Cast<TileLayer>());
break;
case NotifyCollectionChangedAction.Reset:
tileContainer.ClearTileLayers();
if (eventArgs.NewItems != null)
if (e.NewItems != null)
{
tileContainer.AddTileLayers(0, eventArgs.NewItems.Cast<TileLayer>());
tileContainer.AddTileLayers(0, e.NewItems.Cast<TileLayer>());
}
break;
}
@ -619,7 +619,7 @@ namespace MapControl
}
}
private void CenterAnimationCompleted(object sender, EventArgs eventArgs)
private void CenterAnimationCompleted(object sender, EventArgs e)
{
Center = TargetCenter;
centerAnimation.Completed -= CenterAnimationCompleted;
@ -669,7 +669,7 @@ namespace MapControl
}
}
private void ZoomLevelAnimationCompleted(object sender, EventArgs eventArgs)
private void ZoomLevelAnimationCompleted(object sender, EventArgs e)
{
ZoomLevel = TargetZoomLevel;
zoomLevelAnimation.Completed -= ZoomLevelAnimationCompleted;
@ -729,7 +729,7 @@ namespace MapControl
}
}
private void HeadingAnimationCompleted(object sender, EventArgs eventArgs)
private void HeadingAnimationCompleted(object sender, EventArgs e)
{
Heading = TargetHeading;
headingAnimation.Completed -= HeadingAnimationCompleted;

View file

@ -14,7 +14,8 @@ namespace MapControl
{
static MapElement()
{
MapPanel.ParentMapPropertyKey.OverrideMetadata(typeof(MapElement),
MapPanel.ParentMapPropertyKey.OverrideMetadata(
typeof(MapElement),
new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.Inherits, ParentMapPropertyChanged));
}
@ -31,14 +32,14 @@ namespace MapControl
protected abstract void OnViewportChanged();
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MapElement mapElement = obj as MapElement;
if (mapElement != null)
{
Map oldParentMap = eventArgs.OldValue as Map;
Map newParentMap = eventArgs.NewValue as Map;
Map oldParentMap = e.OldValue as Map;
Map newParentMap = e.NewValue as Map;
if (oldParentMap != null)
{

View file

@ -19,41 +19,41 @@ namespace MapControl
set { mouseWheelZoom = value; }
}
protected override void OnMouseWheel(MouseWheelEventArgs eventArgs)
protected override void OnMouseWheel(MouseWheelEventArgs e)
{
base.OnMouseWheel(eventArgs);
base.OnMouseWheel(e);
ZoomMap(eventArgs.GetPosition(this), TargetZoomLevel + mouseWheelZoom * Math.Sign(eventArgs.Delta));
ZoomMap(e.GetPosition(this), TargetZoomLevel + mouseWheelZoom * Math.Sign(e.Delta));
}
protected override void OnMouseRightButtonDown(MouseButtonEventArgs eventArgs)
protected override void OnMouseRightButtonDown(MouseButtonEventArgs e)
{
base.OnMouseRightButtonDown(eventArgs);
base.OnMouseRightButtonDown(e);
if (eventArgs.ClickCount == 2)
if (e.ClickCount == 2)
{
ZoomMap(eventArgs.GetPosition(this), Math.Ceiling(ZoomLevel - 1.5));
ZoomMap(e.GetPosition(this), Math.Ceiling(ZoomLevel - 1.5));
}
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs eventArgs)
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonDown(eventArgs);
base.OnMouseLeftButtonDown(e);
if (eventArgs.ClickCount == 1)
if (e.ClickCount == 1)
{
mousePosition = eventArgs.GetPosition(this);
mousePosition = e.GetPosition(this);
CaptureMouse();
}
else if (eventArgs.ClickCount == 2)
else if (e.ClickCount == 2)
{
ZoomMap(eventArgs.GetPosition(this), Math.Floor(ZoomLevel + 1.5));
ZoomMap(e.GetPosition(this), Math.Floor(ZoomLevel + 1.5));
}
}
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs eventArgs)
protected override void OnMouseLeftButtonUp(MouseButtonEventArgs e)
{
base.OnMouseLeftButtonUp(eventArgs);
base.OnMouseLeftButtonUp(e);
if (mousePosition.HasValue)
{
@ -62,24 +62,24 @@ namespace MapControl
}
}
protected override void OnMouseMove(MouseEventArgs eventArgs)
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(eventArgs);
base.OnMouseMove(e);
if (mousePosition.HasValue)
{
Point position = eventArgs.GetPosition(this);
Point position = e.GetPosition(this);
TranslateMap(position - mousePosition.Value);
mousePosition = position;
}
}
protected override void OnManipulationDelta(ManipulationDeltaEventArgs eventArgs)
protected override void OnManipulationDelta(ManipulationDeltaEventArgs e)
{
base.OnManipulationDelta(eventArgs);
base.OnManipulationDelta(e);
ManipulationDelta d = eventArgs.DeltaManipulation;
TransformMap(eventArgs.ManipulationOrigin, d.Translation, d.Rotation, (d.Scale.X + d.Scale.Y) / 2d);
ManipulationDelta d = e.DeltaManipulation;
TransformMap(e.ManipulationOrigin, d.Translation, d.Rotation, (d.Scale.X + d.Scale.Y) / 2d);
}
}
}

View file

@ -21,24 +21,26 @@ namespace MapControl
[TemplateVisualState(Name = "Current", GroupName = "CurrentStates")]
public class MapItem : ContentControl
{
public static readonly RoutedEvent SelectedEvent = ListBoxItem.SelectedEvent.AddOwner(typeof(MapItem));
public static readonly RoutedEvent UnselectedEvent = ListBoxItem.UnselectedEvent.AddOwner(typeof(MapItem));
public static readonly RoutedEvent SelectedEvent = Selector.SelectedEvent.AddOwner(typeof(MapItem));
public static readonly RoutedEvent UnselectedEvent = Selector.UnselectedEvent.AddOwner(typeof(MapItem));
public static readonly DependencyProperty IsSelectedProperty = Selector.IsSelectedProperty.AddOwner(
typeof(MapItem), new FrameworkPropertyMetadata((o, e) => ((MapItem)o).IsSelectedChanged((bool)e.NewValue)));
private static readonly DependencyPropertyKey IsCurrentPropertyKey = DependencyProperty.RegisterReadOnly(
"IsCurrent", typeof(bool), typeof(MapItem), null);
public static readonly DependencyProperty IsCurrentProperty = IsCurrentPropertyKey.DependencyProperty;
typeof(MapItem),
new FrameworkPropertyMetadata((o, e) => ((MapItem)o).IsSelectedPropertyChanged((bool)e.NewValue)));
static MapItem()
{
FrameworkElement.DefaultStyleKeyProperty.OverrideMetadata(
typeof(MapItem), new FrameworkPropertyMetadata(typeof(MapItem)));
UIElement.IsEnabledProperty.OverrideMetadata(
typeof(MapItem), new FrameworkPropertyMetadata((o, e) => ((MapItem)o).CommonStateChanged()));
MapItemsControl.IsCurrentPropertyKey.OverrideMetadata(
typeof(MapItem),
new FrameworkPropertyMetadata((o, e) => ((MapItem)o).IsCurrentPropertyChanged((bool)e.NewValue)));
}
public MapItem()
{
IsEnabledChanged += IsEnabledPropertyChanged;
}
public event RoutedEventHandler Selected
@ -53,11 +55,6 @@ namespace MapControl
remove { RemoveHandler(UnselectedEvent, value); }
}
public Map ParentMap
{
get { return MapPanel.GetParentMap(this); }
}
public bool IsSelected
{
get { return (bool)GetValue(IsSelectedProperty); }
@ -66,70 +63,37 @@ namespace MapControl
public bool IsCurrent
{
get { return (bool)GetValue(IsCurrentProperty); }
internal set
{
if (IsCurrent != value)
{
SetValue(IsCurrentPropertyKey, value);
int zIndex = Panel.GetZIndex(this);
Panel.SetZIndex(this, value ? (zIndex | 0x40000000) : (zIndex & ~0x40000000));
VisualStateManager.GoToState(this, value ? "Current" : "NotCurrent", true);
}
}
get { return MapItemsControl.GetIsCurrent(this); }
}
public object Item { get; internal set; }
public Map ParentMap
{
get { return MapPanel.GetParentMap(this); }
}
protected override void OnMouseEnter(MouseEventArgs e)
{
base.OnMouseEnter(e);
CommonStateChanged();
if (IsEnabled)
{
VisualStateManager.GoToState(this, "MouseOver", true);
}
}
protected override void OnMouseLeave(MouseEventArgs e)
{
base.OnMouseLeave(e);
CommonStateChanged();
}
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs eventArgs)
{
base.OnMouseLeftButtonDown(eventArgs);
eventArgs.Handled = true;
IsSelected = !IsSelected;
}
protected override void OnTouchDown(TouchEventArgs eventArgs)
{
base.OnTouchDown(eventArgs);
eventArgs.Handled = true; // get TouchUp event
}
protected override void OnTouchUp(TouchEventArgs eventArgs)
{
base.OnTouchUp(eventArgs);
eventArgs.Handled = true;
IsSelected = !IsSelected;
}
private void IsSelectedChanged(bool isSelected)
{
if (isSelected)
if (IsEnabled)
{
VisualStateManager.GoToState(this, "Selected", true);
RaiseEvent(new RoutedEventArgs(SelectedEvent));
}
else
{
VisualStateManager.GoToState(this, "Unselected", true);
RaiseEvent(new RoutedEventArgs(UnselectedEvent));
VisualStateManager.GoToState(this, "Normal", true);
}
}
private void CommonStateChanged()
private void IsEnabledPropertyChanged(object sender, DependencyPropertyChangedEventArgs e)
{
if (!IsEnabled)
if (!(bool)e.NewValue)
{
VisualStateManager.GoToState(this, "Disabled", true);
}
@ -142,5 +106,35 @@ namespace MapControl
VisualStateManager.GoToState(this, "Normal", true);
}
}
private void IsSelectedPropertyChanged(bool isSelected)
{
if (isSelected)
{
RaiseEvent(new RoutedEventArgs(SelectedEvent));
VisualStateManager.GoToState(this, "Selected", true);
}
else
{
RaiseEvent(new RoutedEventArgs(UnselectedEvent));
VisualStateManager.GoToState(this, "Unselected", true);
}
}
private void IsCurrentPropertyChanged(bool isCurrent)
{
int zIndex = Panel.GetZIndex(this);
if (isCurrent)
{
Panel.SetZIndex(this, zIndex | 0x40000000);
VisualStateManager.GoToState(this, "Current", true);
}
else
{
Panel.SetZIndex(this, zIndex & ~0x40000000);
VisualStateManager.GoToState(this, "NotCurrent", true);
}
}
}
}

View file

@ -3,40 +3,46 @@
// Licensed under the Microsoft Public License (Ms-PL)
using System;
using System.Collections;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
namespace MapControl
{
public enum MapItemSelectionMode { Single, Extended }
/// <summary>
/// Manages a collection of selectable items on a Map. Uses MapItem as container for items
/// and updates the MapItem.IsCurrent property when Items.CurrentItem changes.
/// and updates the IsCurrent attached property when the Items.CurrentItem property changes.
/// </summary>
public class MapItemsControl : MultiSelector
{
public static readonly DependencyProperty SelectionModeProperty = DependencyProperty.Register(
"SelectionMode", typeof(MapItemSelectionMode), typeof(MapItemsControl),
new FrameworkPropertyMetadata((o, e) => ((MapItemsControl)o).CanSelectMultipleItems = (MapItemSelectionMode)e.NewValue != MapItemSelectionMode.Single));
"SelectionMode", typeof(SelectionMode), typeof(MapItemsControl),
new FrameworkPropertyMetadata((o, e) => ((MapItemsControl)o).CanSelectMultipleItems = (SelectionMode)e.NewValue != SelectionMode.Single));
public static readonly DependencyProperty SelectionGeometryProperty = DependencyProperty.Register(
"SelectionGeometry", typeof(Geometry), typeof(MapItemsControl),
new FrameworkPropertyMetadata((o, e) => ((MapItemsControl)o).SelectionGeometryChanged((Geometry)e.NewValue)));
new FrameworkPropertyMetadata((o, e) => ((MapItemsControl)o).SelectionGeometryPropertyChanged((Geometry)e.NewValue)));
internal static readonly DependencyPropertyKey IsCurrentPropertyKey = DependencyProperty.RegisterAttachedReadOnly(
"IsCurrent", typeof(bool), typeof(MapItemsControl), null);
public static readonly DependencyProperty IsCurrentProperty = IsCurrentPropertyKey.DependencyProperty;
public MapItemsControl()
{
CanSelectMultipleItems = false;
Style = (Style)FindResource(typeof(MapItemsControl));
CanSelectMultipleItems = SelectionMode != SelectionMode.Single;
Items.CurrentChanging += OnCurrentItemChanging;
Items.CurrentChanged += OnCurrentItemChanged;
}
public MapItemSelectionMode SelectionMode
public SelectionMode SelectionMode
{
get { return (MapItemSelectionMode)GetValue(SelectionModeProperty); }
get { return (SelectionMode)GetValue(SelectionModeProperty); }
set { SetValue(SelectionModeProperty, value); }
}
@ -46,26 +52,34 @@ namespace MapControl
set { SetValue(SelectionGeometryProperty, value); }
}
public MapItem GetMapItem(object item)
public static bool GetIsCurrent(UIElement element)
{
return item != null ? ItemContainerGenerator.ContainerFromItem(item) as MapItem : null;
return (bool)element.GetValue(IsCurrentProperty);
}
public object GetHitItem(Point point)
public static void SetIsCurrent(UIElement element, bool value)
{
DependencyObject obj = InputHitTest(point) as DependencyObject;
element.SetValue(IsCurrentPropertyKey, value);
}
while (obj != null)
{
if (obj is MapItem)
{
return ((MapItem)obj).Item;
}
public UIElement GetContainer(object item)
{
return item != null ? ItemContainerGenerator.ContainerFromItem(item) as UIElement : null;
}
obj = VisualTreeHelper.GetParent(obj);
}
public object GetItem(DependencyObject container)
{
return container != null ? ItemContainerGenerator.ItemFromContainer(container) : null;
}
return null;
public IList GetItemsInGeometry(Geometry geometry)
{
return GetItemsInGeometry(geometry, new ArrayList(Items.Count), Items.Count);
}
protected override bool IsItemItsOwnContainerOverride(object item)
{
return item is UIElement;
}
protected override DependencyObject GetContainerForItemOverride()
@ -75,63 +89,118 @@ namespace MapControl
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
MapItem mapItem = (MapItem)element;
mapItem.Item = item;
base.PrepareContainerForItemOverride(element, item);
UIElement container = (UIElement)element;
container.MouseLeftButtonDown += ContainerMouseLeftButtonDown;
container.TouchDown += ContainerTouchDown;
container.TouchUp += ContainerTouchUp;
}
protected override void ClearContainerForItemOverride(DependencyObject element, object item)
{
MapItem mapItem = (MapItem)element;
mapItem.Item = null;
base.ClearContainerForItemOverride(element, item);
UIElement container = (UIElement)element;
container.MouseLeftButtonDown -= ContainerMouseLeftButtonDown;
container.TouchDown -= ContainerTouchDown;
container.TouchUp -= ContainerTouchUp;
}
private void OnCurrentItemChanging(object sender, CurrentChangingEventArgs eventArgs)
private void ContainerMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
MapItem mapItem = GetMapItem(Items.CurrentItem);
e.Handled = true;
UIElement container = (UIElement)sender;
if (mapItem != null)
if (SelectionMode == SelectionMode.Extended &&
(Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == 0)
{
mapItem.IsCurrent = false;
SelectedItem = GetItem(container);
}
else
{
Selector.SetIsSelected(container, !Selector.GetIsSelected(container));
}
}
private void OnCurrentItemChanged(object sender, EventArgs eventArgs)
private void ContainerTouchDown(object sender, TouchEventArgs e)
{
MapItem mapItem = GetMapItem(Items.CurrentItem);
e.Handled = true; // get TouchUp event
}
if (mapItem != null)
private void ContainerTouchUp(object sender, TouchEventArgs e)
{
e.Handled = true;
UIElement container = (UIElement)sender;
Selector.SetIsSelected(container, !Selector.GetIsSelected(container));
}
private void OnCurrentItemChanging(object sender, CurrentChangingEventArgs e)
{
UIElement container = GetContainer(Items.CurrentItem);
if (container != null)
{
mapItem.IsCurrent = true;
SetIsCurrent(container, false);
}
}
private void SelectionGeometryChanged(Geometry geometry)
private void OnCurrentItemChanged(object sender, EventArgs e)
{
UIElement container = GetContainer(Items.CurrentItem);
if (container != null)
{
SetIsCurrent(container, true);
}
}
private void SelectionGeometryPropertyChanged(Geometry geometry)
{
if (geometry != null)
{
SelectionMode = MapItemSelectionMode.Extended;
BeginUpdateSelectedItems();
SelectedItems.Clear();
if (!geometry.IsEmpty())
if (SelectionMode == SelectionMode.Single)
{
foreach (object item in Items)
{
MapItem mapItem = GetMapItem(item);
ViewportPosition viewportPosition = MapPanel.GetViewportPosition(mapItem);
IList items = GetItemsInGeometry(geometry, new ArrayList(1), 1);
SelectedItem = items.Count > 0 ? items[0] : null;
}
else
{
BeginUpdateSelectedItems();
GetItemsInGeometry(geometry, SelectedItems, Items.Count);
EndUpdateSelectedItems();
}
}
}
if (mapItem != null && viewportPosition != null && geometry.FillContains(viewportPosition.Position))
private IList GetItemsInGeometry(Geometry geometry, IList items, int maxItems)
{
items.Clear();
if (!geometry.IsEmpty())
{
foreach (object item in Items)
{
UIElement container = GetContainer(item);
if (container != null)
{
ViewportPosition viewportPosition = MapPanel.GetViewportPosition(container);
if (viewportPosition != null && geometry.FillContains(viewportPosition.Position))
{
SelectedItems.Add(item);
items.Add(item);
if (items.Count >= maxItems)
{
break;
}
}
}
}
EndUpdateSelectedItems();
}
return items;
}
}
}

View file

@ -109,14 +109,14 @@ namespace MapControl
}
}
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
private static void ParentMapPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
MapPanel mapPanel = obj as MapPanel;
if (mapPanel != null)
{
Map oldParentMap = eventArgs.OldValue as Map;
Map newParentMap = eventArgs.NewValue as Map;
Map oldParentMap = e.OldValue as Map;
Map newParentMap = e.NewValue as Map;
if (oldParentMap != null && oldParentMap != mapPanel)
{
@ -130,13 +130,13 @@ namespace MapControl
}
}
private static void ViewportPositionPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
private static void ViewportPositionPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
UIElement element = obj as UIElement;
if (element != null)
{
ViewportPosition position = (ViewportPosition)eventArgs.NewValue;
ViewportPosition position = (ViewportPosition)e.NewValue;
if (position != null)
{
@ -149,13 +149,13 @@ namespace MapControl
}
}
private static void LocationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs eventArgs)
private static void LocationPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
{
UIElement element = obj as UIElement;
if (element != null)
{
SetViewportPosition(element, GetParentMap(element), (Location)eventArgs.NewValue);
SetViewportPosition(element, GetParentMap(element), (Location)e.NewValue);
}
}

View file

@ -149,9 +149,9 @@ namespace MapControl
return visual;
}
protected override void OnInitialized(EventArgs eventArgs)
protected override void OnInitialized(EventArgs e)
{
base.OnInitialized(eventArgs);
base.OnInitialized(e);
AddVisualChild(visual);
}

View file

@ -114,7 +114,7 @@ namespace MapControl
return transform;
}
private void UpdateTiles(object sender, EventArgs eventArgs)
private void UpdateTiles(object sender, EventArgs e)
{
updateTimer.IsEnabled = false;