// (c) Copyright ESRI. // This source is subject to the Microsoft Public License (Ms-PL). // Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details. // All other rights reserved. using System; using System.Net; using System.Windows; using System.Windows.Controls; using System.Windows.Documents; using System.Windows.Ink; using System.Windows.Input; using System.Windows.Media; using System.Windows.Media.Animation; using System.Windows.Shapes; using System.Collections.Generic; namespace ESRI.ArcGIS.Client.Toolkit { /// /// Graphics Layer MapTip control /// [TemplateVisualState(Name = "Collapsed", GroupName = "CommonStates")] [TemplateVisualState(Name = "Expanded", GroupName = "CommonStates")] public class MapTip : Control { private System.Windows.Threading.DispatcherTimer timer; private TimeSpan maptipDelay = new TimeSpan(0, 0, 0, 0, 500); /// /// Initializes a new instance of the class. /// public MapTip() { #if SILVERLIGHT DefaultStyleKey = typeof(MapTip); #endif this.Visibility = Visibility.Collapsed; HorizontalOffset = 20; VerticalOffset = 30; enterHandler = graphicsLayer_MouseEnter; leaveHandler = graphicsLayer_MouseLeave; moveHandler = graphicsLayer_MouseMove; timer = new System.Windows.Threading.DispatcherTimer() { Interval = maptipDelay }; timer.Tick += new EventHandler(timer_Tick); this.MouseEnter += new MouseEventHandler(MapTip_MouseEnter); this.MouseLeave += new MouseEventHandler(MapTip_MouseLeave); this.MouseLeftButtonUp += new MouseButtonEventHandler(MapTip_MouseLeftButtonUp); } /// /// Static initialization for the control. /// static MapTip() { #if !SILVERLIGHT DefaultStyleKeyProperty.OverrideMetadata(typeof(MapTip), new FrameworkPropertyMetadata(typeof(MapTip))); #endif } private void MapTip_MouseLeftButtonUp(object sender, MouseButtonEventArgs e) { if (!this.expanded) { this.expanded = true; ChangeVisualState(true); } } /// /// When overridden in a derived class, is invoked whenever application code or internal processes (such as a rebuilding layout pass) call . /// public override void OnApplyTemplate() { base.OnApplyTemplate(); ChangeVisualState(false); } ESRI.ArcGIS.Client.GraphicsLayer.MouseEventHandler enterHandler; ESRI.ArcGIS.Client.GraphicsLayer.MouseEventHandler leaveHandler; ESRI.ArcGIS.Client.GraphicsLayer.MouseEventHandler moveHandler; private bool expanded = false; private void ChangeVisualState(bool useTransitions) { if (expanded) { GoToState(useTransitions, "Expanded"); } else { GoToState(useTransitions, "Collapsed"); } } private bool GoToState(bool useTransitions, string stateName) { return VisualStateManager.GoToState(this, stateName, useTransitions); } /// /// Expands the maptip /// /// if set to true will use transitions. public void Expand(bool useTransitions) { expanded = true; ChangeVisualState(useTransitions); } /// /// Collapses the maptip. /// /// if set to true will use transitions. public void Collapse(bool useTransitions) { expanded = false; ChangeVisualState(useTransitions); } #region Properties /// /// Identifies the dependency property. /// public static readonly DependencyProperty GraphicsLayerProperty = DependencyProperty.Register("GraphicsLayer", typeof(GraphicsLayer), typeof(MapTip), new PropertyMetadata(OnGraphicsLayerPropertyChanged)); private static void OnGraphicsLayerPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { MapTip maptip = d as MapTip; GraphicsLayer newLayer = e.NewValue as GraphicsLayer; GraphicsLayer oldLayer = e.OldValue as GraphicsLayer; if (oldLayer != null) { oldLayer.MouseEnter -= maptip.enterHandler; oldLayer.MouseLeave -= maptip.leaveHandler; oldLayer.MouseMove -= maptip.moveHandler; } maptip.Collapse(false); maptip.Visibility = Visibility.Collapsed; maptip.currentFeature = null; maptip.ItemsSource = null; maptip.DataContext = null; if (newLayer != null) { newLayer.MouseEnter += maptip.enterHandler; newLayer.MouseLeave += maptip.leaveHandler; newLayer.MouseMove += maptip.moveHandler; } } /// /// Gets or sets the graphics layer that the maptip is associated with. /// public ESRI.ArcGIS.Client.GraphicsLayer GraphicsLayer { get { return GetValue(GraphicsLayerProperty) as GraphicsLayer; } set { SetValue(GraphicsLayerProperty, value); } } /// /// Identifies the dependency property. /// public static readonly DependencyProperty TitleMemberProperty = DependencyProperty.Register("TitleMember", typeof(string), typeof(MapTip), null); /// /// Gets or sets the Graphic Attribute Key used for setting the title /// on the MapTip. This is overridden if the property is set. /// /// The map tip title member. public string TitleMember { get { return (string)GetValue(TitleMemberProperty); } set { SetValue(TitleMemberProperty, value); } } /// /// Identifies the dependency property. /// public static readonly DependencyProperty TitleProperty = DependencyProperty.Register("Title", typeof(object), typeof(MapTip), null); /// /// Gets or sets the title displayed in the MapTip. It can be a either a string or a FrameworkElement. /// It will override any settings set using . /// /// The map tip title. public object Title { get { return (object)GetValue(TitleProperty); } set { SetValue(TitleProperty, value); } } /// /// Identifies the dependency property. /// public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register("HorizontalOffset", typeof(int), typeof(MapTip), new PropertyMetadata(0, OnHorizontalOffsetPropertyChanged)); private static void OnHorizontalOffsetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { MapTip dp = d as MapTip; int dX = (int)e.NewValue - (int)e.OldValue; dp.SetValue(Canvas.LeftProperty, Canvas.GetLeft(dp) + dX); } /// /// Identifies the dependency property. /// public static readonly DependencyProperty VerticalOffsetProperty = DependencyProperty.Register("VerticalOffset", typeof(int), typeof(MapTip), new PropertyMetadata(0, OnVerticalOffsetPropertyChanged)); private static void OnVerticalOffsetPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { MapTip dp = d as MapTip; int dY = (int)e.NewValue - (int)e.OldValue; dp.SetValue(Canvas.TopProperty, Canvas.GetTop(dp) + dY); } /// /// Gets or sets the horizontal offset. /// /// The horizontal offset. public int HorizontalOffset { get { return (int)GetValue(HorizontalOffsetProperty); } set { SetValue(HorizontalOffsetProperty, value); } } /// /// Gets or sets the vertical offset. /// /// The vertical offset. public int VerticalOffset { get { return (int)GetValue(VerticalOffsetProperty); } set { SetValue(VerticalOffsetProperty, value); } } /// /// Identifies the dependency property. /// public static readonly DependencyProperty ItemsSourceProperty = DependencyProperty.Register("ItemsSource", typeof(System.Collections.IEnumerable), typeof(MapTip), null); /// /// Gets or sets the items source used for data binding. /// /// The items source. public System.Collections.IEnumerable ItemsSource { get { return (System.Collections.IEnumerable)GetValue(ItemsSourceProperty); } private set { SetValue(ItemsSourceProperty, value); } } #endregion #region Mouse Graphic Events /// The current active feature private ESRI.ArcGIS.Client.Graphic currentFeature; /// True if the mouse is over either the graphic or the maptip private bool mouseIsOver = false; private void timer_Tick(object sender, EventArgs e) { timer.Stop(); if (mouseIsOver) { Visibility = Visibility.Visible; } else { Visibility = Visibility.Collapsed; } } private void graphicsLayer_MouseMove(object sender, GraphicMouseEventArgs e) { //Recenter the maptip as long as the maptip isn't displaying yet if (Visibility == Visibility.Collapsed) { Point p = e.GetPosition(Parent as UIElement); SetValue(Canvas.LeftProperty, p.X + HorizontalOffset); SetValue(Canvas.TopProperty, p.Y + VerticalOffset); timer.Start(); } } private void MapTip_MouseLeave(object sender, MouseEventArgs e) { mouseIsOver = false; if (timer.IsEnabled) { timer.Stop(); } //Cancel the show timer if (Visibility == Visibility.Visible) { timer.Start(); //Delay hiding maptip } } private void MapTip_MouseEnter(object sender, MouseEventArgs e) { mouseIsOver = true; if (timer.IsEnabled) { timer.Stop(); } //Cancel the hide timer if (Visibility == Visibility.Collapsed) { timer.Start(); //Delay showing maptip } } private void graphicsLayer_MouseLeave(object sender, GraphicMouseEventArgs args) { if (timer.IsEnabled) { timer.Stop(); } if (Visibility == Visibility.Visible) { timer.Start(); //Delay hiding maptip } mouseIsOver = false; } private void graphicsLayer_MouseEnter(object sender, GraphicMouseEventArgs args) { mouseIsOver = true; Graphic graphic = args.Graphic; if (currentFeature != graphic) //Mouse entered a new feature { this.expanded = false; currentFeature = graphic; Point p = args.GetPosition(Parent as UIElement); SetValue(Canvas.LeftProperty, p.X + HorizontalOffset); SetValue(Canvas.TopProperty, p.Y + VerticalOffset); this.DataContext = this.ItemsSource = graphic.Attributes; if (!string.IsNullOrEmpty(TitleMember)) { object title = null; if (graphic.Attributes.ContainsKey(TitleMember)) title = string.Format("{0}", graphic.Attributes[TitleMember]); else { string firstKey = null; foreach (string key in graphic.Attributes.Keys) { if (firstKey == null) firstKey = key; if (graphic.Attributes[key].GetType() == typeof(string)) { title = graphic.Attributes[key] as string; break; } } if (title == null && !string.IsNullOrEmpty(firstKey)) title = string.Format("{0}", graphic.Attributes[firstKey]); } this.Title = title; } ChangeVisualState(false); Visibility = Visibility.Collapsed; } if (Visibility == Visibility.Collapsed) { timer.Start(); //Delay showing maptip } } #endregion } }