// Copyright 2014-, SharpMapTeam // // This file is part of SharpMap. // SharpMap is free software; you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation; either version 2 of the License, or // (at your option) any later version. // // SharpMap is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public License // along with SharpMap; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System.ComponentModel; using System.Drawing.Drawing2D; using KeyEventArgs = System.Windows.Input.KeyEventArgs; using MouseEventArgs = System.Windows.Forms.MouseEventArgs; namespace SharpMap.UI.WPF { using System.Collections.Generic; using System.Collections.ObjectModel; using System.Collections.Specialized; using System.Drawing; using System.Linq; using System.Windows; using System.Windows.Forms.Integration; using System.Windows.Input; using GeoAPI.Geometries; using Data.Providers; using Forms; using Layers; using Rendering.Decoration; using Rendering.Decoration.ScaleBar; using KeyEventArgs = KeyEventArgs; using MouseEventArgs = MouseEventArgs; /// /// Extends WindowsFormsHost and encapsulates SharpMap specific code. /// public class SharpMapHost : WindowsFormsHost, INotifyPropertyChanged { // Dependency Property to store MapLayers. public static readonly DependencyProperty MapLayersProperty = DependencyProperty.Register("MapLayers", typeof (ObservableCollection), typeof (SharpMapHost), new PropertyMetadata(SetMapLayersCallback)); // Dependency Property store store BackgroundLayer. public static readonly DependencyProperty BackgroundLayerProperty = DependencyProperty.Register("BackgroundLayer", typeof (Layer), typeof (SharpMapHost), new PropertyMetadata(SetBackgroundLayerCallback)); // Dependency Property to store ActiveTool. public static readonly DependencyProperty ActiveToolProperty = DependencyProperty.Register("ActiveTool", typeof (MapBox.Tools), typeof (SharpMapHost), new PropertyMetadata(SetActiveToolCallback)); // Dependency Property to store MaxExtent. public static readonly DependencyProperty MaxExtentProperty = DependencyProperty.Register("MaxExtent", typeof (Envelope), typeof (SharpMapHost), new PropertyMetadata(SetMaxExtentCallback)); // Dependency Property to store MapExtent. public static readonly DependencyProperty MapExtentProperty = DependencyProperty.Register("MapExtent", typeof (Envelope), typeof (SharpMapHost), new PropertyMetadata(MapExtentCallback)); // Dependency Property to store Rotation kept in MapTransform public static readonly DependencyProperty MapRotationProperty = DependencyProperty.Register("MapRotation", typeof(float), typeof(SharpMapHost), new PropertyMetadata(MapRotationCallback)); // Dependency Property used when a new geometry is defined. public static readonly DependencyProperty DefinedGeometryProperty = DependencyProperty.Register("DefinedGeometry", typeof (IGeometry), typeof (SharpMapHost), new PropertyMetadata(GeometryDefinedCallback)); // Dependency Property used when right click in a MapFeature. public static readonly DependencyProperty FeatureRightClickedCommandProperty = DependencyProperty.Register("FeatureRightClickedCommand", typeof (ICommand), typeof (SharpMapHost)); private readonly MapBox _mapBox; private VectorLayer _editLayer; private GeometryProvider _editLayerGeoProvider; private Coordinate _currentMouseCoordinate; /// /// Initializes a new instance of the class. /// public SharpMapHost() { _mapBox = new MapBox{ BackColor = Color.White, Map = new Map{ SRID = 900913 } }; Child = _mapBox; MapLayers = new ObservableCollection(); var scaleBar = new ScaleBar{ Anchor = MapDecorationAnchor.LeftBottom }; _mapBox.Map.Decorations.Add(scaleBar); _mapBox.PanOnClick = false; KeyDown += OnKeyDown; _mapBox.MouseMove += MapBoxOnMouseMove; } public ObservableCollection MapLayers { get { return (ObservableCollection) GetValue(MapLayersProperty); } set { SetValue(MapLayersProperty, value); } } public Layer BackgroundLayer { get { return (Layer) GetValue(BackgroundLayerProperty); } set { SetValue(BackgroundLayerProperty, value); } } public MapBox.Tools ActiveTool { get { return (MapBox.Tools) GetValue(ActiveToolProperty); } set { SetValue(ActiveToolProperty, value); } } public string CurrentMouseCoordinateString { get { return _currentMouseCoordinate != null ? string.Format("{0:0}, {1:0}", _currentMouseCoordinate.X, _currentMouseCoordinate.Y) : ""; } } public Coordinate CurrentMouseCoordinate { get { return _currentMouseCoordinate; } } public Envelope MaxExtent { get { return (Envelope) GetValue(MaxExtentProperty); } set { SetValue(MaxExtentProperty, value); } } public Envelope MapExtent { get { return _mapBox.Map.Envelope; } set { SetValue(MapExtentProperty, value); } } public float MapRotation { get { return _mapBox.Map.MapTransformRotation; } set { SetValue(MapRotationProperty, value); } } public IGeometry DefinedGeometry { get { return (IGeometry) GetValue(DefinedGeometryProperty); } set { SetValue(DefinedGeometryProperty, value); } } /// /// The command that is invoked when a feature is right clicked /// public ICommand FeatureRightClickedCommand { get { return GetValue(FeatureRightClickedCommandProperty) as ICommand; } set { SetValue(FeatureRightClickedCommandProperty, value); } } /// /// Gets called when changes on MapLayers /// /// The sender object /// The event arguments private static void SetMapLayersCallback(object sender, DependencyPropertyChangedEventArgs args) { var host = sender as SharpMapHost; if (host == null) { return; } var oldLayers = args.OldValue as ObservableCollection; if (oldLayers != null) { oldLayers.CollectionChanged -= host.OnMapLayerChanged; } var newLayers = args.NewValue as ObservableCollection; if (newLayers != null) { newLayers.CollectionChanged += host.OnMapLayerChanged; } } /// /// Gets called when changes on BackgroundLayer /// /// The sender object /// The event arguments private static void SetBackgroundLayerCallback(object sender, DependencyPropertyChangedEventArgs args) { var host = sender as SharpMapHost; if (host == null) { return; } var mapBox = host._mapBox; var layer = args.NewValue as Layer; if (layer != null) { mapBox.Map.BackgroundLayer.Add(layer); } mapBox.Refresh(); } /// /// Gets called when changes on ActiveTool /// /// The sender object /// The event arguments private static void SetActiveToolCallback(object sender, DependencyPropertyChangedEventArgs args) { var host = sender as SharpMapHost; if (host == null) { return; } var mapBox = host._mapBox; var newTool = (MapBox.Tools) args.NewValue; mapBox.ActiveTool = newTool; } /// /// Gets called when changes on MaxExtent /// /// The sender object /// The event arguments private static void SetMaxExtentCallback(object sender, DependencyPropertyChangedEventArgs args) { var host = sender as SharpMapHost; if (host == null) { return; } var mapBox = host._mapBox; var extent = (Envelope) args.NewValue; if (extent != null) { mapBox.Map.EnforceMaximumExtents = true; mapBox.Map.MaximumExtents = extent; } } /// /// Gets called when changes on MapExtent /// /// The sender object /// The event arguments private static void MapExtentCallback(object sender, DependencyPropertyChangedEventArgs args) { var host = sender as SharpMapHost; if (host == null) { return; } var mapBox = host._mapBox; var extent = (Envelope) args.NewValue; mapBox.Map.ZoomToBox(extent); mapBox.Refresh(); } /// /// Gets called when changes on MapExtent /// /// The sender object /// The event arguments private static void MapRotationCallback(object sender, DependencyPropertyChangedEventArgs args) { var host = sender as SharpMapHost; if (host == null) { return; } var mapBox = host._mapBox; float rotation = (float)args.NewValue; var mapTransform = new Matrix(); mapTransform.RotateAt(rotation, new PointF(mapBox.Width / 2f, mapBox.Height / 2f)); mapBox.Map.MapTransform = mapTransform; mapBox.Refresh(); } /// /// Gets called when changes on GeometryDefined /// /// The sender object /// The event arguments private static void GeometryDefinedCallback(object sender, DependencyPropertyChangedEventArgs args) { var host = sender as SharpMapHost; if (host == null) { return; } if (host._editLayer == null) { host._editLayer = new VectorLayer("EditLayer"); host._editLayerGeoProvider = new GeometryProvider(new List()); host._editLayer.DataSource = host._editLayerGeoProvider; host.MapLayers.Add(host._editLayer); } host._editLayerGeoProvider.Geometries.Clear(); var geom = (IGeometry) args.NewValue; if (geom != null) { host._editLayerGeoProvider.Geometries.Add(geom); } host._mapBox.Refresh(); } /// /// Gets called when keyboard key pressed. Pans the map according to arrow keys. /// /// The sender object /// The event arguments private void OnKeyDown(object sender, KeyEventArgs keyEventArgs) { var currentEnvelope = _mapBox.Map.Envelope; var dX = currentEnvelope.Width/2; var dY = currentEnvelope.Height/2; var x = _mapBox.Map.Center.X; var y = _mapBox.Map.Center.Y; switch (keyEventArgs.Key) { case Key.Left: x -= dX; keyEventArgs.Handled = true; break; case Key.Right: x += dX; keyEventArgs.Handled = true; break; case Key.Up: y += dY; keyEventArgs.Handled = true; break; case Key.Down: y -= dY; keyEventArgs.Handled = true; break; } _mapBox.Map.Center = new Coordinate(x, y); _mapBox.Refresh(); } /// /// Gets called when changes in MapLayers /// /// The sender object /// The event arguments private void OnMapLayerChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) { case NotifyCollectionChangedAction.Add: { var layers = e.NewItems; if (layers != null) { foreach (var layer in layers) { var castedLayer = layer as ILayer; if (castedLayer != null && _mapBox.Map.Layers.All(l => l.LayerName != castedLayer.LayerName)) _mapBox.Map.Layers.Add(castedLayer); } } } break; case NotifyCollectionChangedAction.Remove: { var layers = e.OldItems; if (layers != null) { foreach (var layer in layers) { var castedLayer = layer as ILayer; if (castedLayer != null && _mapBox.Map.Layers.Any(l => l.LayerName == castedLayer.LayerName)) _mapBox.Map.Layers.Remove(castedLayer); } } } break; case NotifyCollectionChangedAction.Reset: _mapBox.Map.Layers.Clear(); break; } _mapBox.Refresh(); } public void ZoomToExtents() { _mapBox.Map.ZoomToExtents(); _mapBox.Refresh(); } public void ZoomToEnvelope(Envelope env) { _mapBox.Map.ZoomToBox(env); _mapBox.Refresh(); } /// /// Gets called when mouse moves over map /// /// The click coordinate /// The event arguments private void MapBoxOnMouseMove(Coordinate worldPos, MouseEventArgs mouseEventArgs) { _currentMouseCoordinate = worldPos; if (PropertyChanged != null) { PropertyChanged(this, new PropertyChangedEventArgs("CurrentMouseCoordinate")); PropertyChanged(this, new PropertyChangedEventArgs("CurrentMouseCoordinateString")); } } public event PropertyChangedEventHandler PropertyChanged; } }