Editor.cs
上传用户:huazai0421
上传日期:2008-05-30
资源大小:405k
文件大小:22k
源码类别:

SilverLight

开发平台:

C#

  1. using System;
  2. using System.Collections.Generic;
  3. using System.Windows;
  4. using System.Windows.Input;
  5. using System.Windows.Threading;
  6. using ESRI.ArcGIS.Client;
  7. using ESRI.ArcGIS.Client.Geometry;
  8. using ESRI.ArcGIS.Client.Symbols;
  9. namespace ESRI.ArcGIS.Samples
  10. {
  11. /// <summary>
  12. /// GraphicLayer editor
  13. /// </summary>
  14. public class Editor
  15. {
  16. public enum Action
  17. {
  18. VertexAdded,
  19. VertexRemoved,
  20. VextedMoved,
  21. EditCompleted,
  22. EditStarted
  23. }
  24. public sealed class GeometryEditEventArgs : EventArgs
  25. {
  26. internal GeometryEditEventArgs(Graphic g, MapPoint newItem, MapPoint oldItem, Action action)
  27. : this(g, newItem == null ? null : new MapPoint[] { newItem },
  28. oldItem == null ? null : new MapPoint[] { oldItem }, action)
  29. { }
  30. internal GeometryEditEventArgs(Graphic g, MapPoint[] newItems, MapPoint[] oldItems, Action action)
  31. {
  32. Graphic = g;
  33. NewItems = newItems;
  34. OldItems = oldItems;
  35. Action = action;
  36. }
  37. public Graphic Graphic { get; private set; }
  38. public MapPoint[] NewItems { get; private set; }
  39. public MapPoint[] OldItems { get; private set; }
  40. public Action Action { get; private set; }
  41. }
  42. #region Private fields
  43. /// <summary>Invisible line symbol for tragging mouse move on polygon edges and polylines</summary>
  44. SimpleLineSymbol hoverLine = new SimpleLineSymbol(System.Windows.Media.Colors.Transparent, 10);
  45. /// <summary>Vertex symbol while dragging the polygon</summary>
  46. MarkerSymbol draggingVertexSymbol = new SimpleMarkerSymbol() { Size = 7, Color = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.Yellow) };
  47. /// <summary>Snap Symbol when hovering on the line segments</summary>
  48. MarkerSymbol snapSymbol = new SimpleMarkerSymbol()
  49. {
  50. Size = 8,
  51. Color = new System.Windows.Media.SolidColorBrush(
  52. System.Windows.Media.Color.FromArgb(200, 255, 255, 0))
  53. };
  54. private Graphic snapVertex;
  55. private Graphic DraggingVertex;
  56. private Graphic activeGraphic;
  57. private GraphicsLayer vertexLayer;
  58. private Map MyMap;
  59. private GraphicsLayer editLayer;
  60. private bool enabled;
  61. #endregion
  62. public event EventHandler<GeometryEditEventArgs> GeometryEdit;
  63. /// <summary>Symbol for each vertex in a polygon or polyline</summary>
  64. public MarkerSymbol VertexSymbol { get; set; }
  65. /// <summary>
  66. /// Initializes a new instance of the <see cref="Editor"/> class.
  67. /// </summary>
  68. /// <param name="map">The map you're editing on.</param>
  69. /// <param name="layer">The layer you want to edit.</param>
  70. public Editor(Map map, GraphicsLayer layer)
  71. {
  72. MyMap = map;
  73. editLayer = layer;
  74. VertexSymbol = new SimpleMarkerSymbol()
  75. {
  76. Size = 7,
  77. Style = SimpleMarkerSymbol.SimpleMarkerStyle.Square,
  78. Color = new System.Windows.Media.SolidColorBrush(System.Windows.Media.Colors.White)
  79. };
  80. }
  81. /// <summary>
  82. /// Gets or sets a value indicating whether editing is enabled.
  83. /// </summary>
  84. /// <value>
  85. ///  <c>true</c> if editing is enabled; otherwise, <c>false</c>.
  86. /// </value>
  87. public bool IsEnabled
  88. {
  89. get { return enabled; }
  90. set
  91. {
  92. if (enabled != value)
  93. {
  94. enabled = value;
  95. if (enabled) Enable();
  96. else Disable();
  97. }
  98. }
  99. }
  100. private void Disable()
  101. {
  102. StopEdit();
  103. editLayer.MouseLeftButtonDown -= GraphicsLayer_MouseLeftButtonDown;
  104. }
  105. private void Enable()
  106. {
  107. editLayer.MouseLeftButtonDown += GraphicsLayer_MouseLeftButtonDown;
  108. }
  109. /// <summary>
  110. /// Called when a feature is clicked. Makes the clicked feature "active" for editing,
  111. /// by creating a set of vertices in an edit layer
  112. /// </summary>
  113. /// <param name="sender">The sender.</param>
  114. /// <param name="graphic">The graphic.</param>
  115. /// <param name="args">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
  116. private void GraphicsLayer_MouseLeftButtonDown(object sender, ESRI.ArcGIS.Client.Graphic graphic, MouseButtonEventArgs args)
  117. {
  118. if (graphic.Geometry is MapPoint)
  119. args.Handled = true;
  120. if (activeGraphic == graphic)
  121. {
  122. StopEdit();
  123. }
  124. else StartEdit(graphic);
  125. }
  126. /// <summary>
  127. /// Starts editing a graphic.
  128. /// </summary>
  129. /// <param name="graphic">The graphic.</param>
  130. public void StartEdit(ESRI.ArcGIS.Client.Graphic graphic)
  131. {
  132. StartEdit(graphic, false);
  133. }
  134. private void StartEdit(ESRI.ArcGIS.Client.Graphic graphic, bool suppressEvent)
  135. {
  136. if (activeGraphic == graphic)
  137. {
  138. return;
  139. }
  140. StopEdit();
  141. //Create vertex graphics layer with all the vertices of the clicked graphic
  142. vertexLayer = new GraphicsLayer();
  143. if (graphic.Geometry is MapPoint) //Points are a little special. We start tracking immediately
  144. {
  145. DraggingVertex = AddVertexToEditLayer(graphic, vertexLayer, graphic.Geometry as MapPoint);
  146. StartTracking();
  147. }
  148. else
  149. {
  150. if (graphic.Geometry is Polyline)
  151. {
  152. Polyline line = graphic.Geometry as Polyline;
  153. foreach (PointCollection ps in line.Paths)
  154. {
  155. BuildHoverLines(graphic, ps, true);
  156. }
  157. }
  158. else if (graphic.Geometry is Polygon)
  159. {
  160. Polygon poly = graphic.Geometry as Polygon;
  161. foreach (PointCollection ps in poly.Rings)
  162. {
  163. BuildHoverLines(graphic, ps, false);
  164. }
  165. }
  166.                 else if (graphic.Geometry is Envelope)
  167.                 {
  168.                     Envelope poly = graphic.Geometry as Envelope;
  169.                     Graphic g = AddVertexToEditLayer(graphic, vertexLayer, new MapPoint(poly.XMin, poly.YMin));
  170.                     g.Attributes.Add("corner", 0);
  171.                     g = AddVertexToEditLayer(graphic, vertexLayer, new MapPoint(poly.XMax, poly.YMax));
  172.                     g.Attributes.Add("corner", 1);
  173.                 }
  174. }
  175. activeGraphic = graphic;
  176. MyMap.Layers.Add(vertexLayer);
  177. //Start listening for mouse down events
  178. vertexLayer.MouseLeftButtonDown += vertexLayer_MouseLeftButtonDown;
  179. vertexLayer.MouseLeave += vertexLayer_MouseLeave;
  180. vertexLayer.MouseMove += vertexLayer_MouseMove;
  181. if (!suppressEvent)
  182. OnGeometryEdit(activeGraphic, null, null, Action.EditStarted);
  183. }
  184. /// <summary>
  185. /// Stops editing a graphic.
  186. /// </summary>
  187. public void StopEdit()
  188. {
  189. StopEdit(false);
  190. }
  191. private void StopEdit(bool suppressEvent)
  192. {
  193. if (vertexLayer != null)
  194. {
  195. vertexLayer.ClearGraphics();
  196. MyMap.Layers.Remove(vertexLayer);
  197. vertexLayer.MouseLeftButtonDown -= GraphicsLayer_MouseLeftButtonDown;
  198. vertexLayer = null;
  199. }
  200. StopTracking();
  201. if (activeGraphic != null && activeGraphic.Geometry is Envelope) //if Envelope correct min/max
  202. {
  203. Envelope env = activeGraphic.Geometry as Envelope;
  204. double x1 = env.XMin;
  205. double x2 = env.XMax;
  206. double y1 = env.YMin;
  207. double y2 = env.YMax;
  208. env.XMin = Math.Min(x1, x2);
  209. env.XMax = Math.Max(x1, x2);
  210. env.YMin = Math.Min(y1, y2);
  211. env.YMax = Math.Max(y1, y2);
  212. }
  213. if (!suppressEvent && activeGraphic != null)
  214. OnGeometryEdit(activeGraphic, null, null, Action.EditCompleted);
  215. activeGraphic = null;
  216. }
  217. /// <summary>
  218. /// Adds hover lines and vertices to track mouseover on the polygon outline and line segments.
  219. /// </summary>
  220. /// <param name="ps">The ps.</param>
  221. /// <param name="includeLastPoint">set to <c>true</c> for lines and <c>false</c> for polygons.</param>
  222. private void BuildHoverLines(Graphic graphic, PointCollection ps, bool includeLastPoint)
  223. {
  224. Graphic first = null;
  225. for (int i = 0; i < ps.Count - 1; i++)
  226. {
  227. Graphic g = AddVertexToEditLayer(graphic, vertexLayer, ps[i]);
  228. if (i == 0) first = g;
  229. MapPoint p0 = ps[i];
  230. MapPoint p1 = ps[i + 1];
  231. AddHoverLineSegment(ps, p0, p1, graphic);
  232. g.Attributes.Add("PointCollection", ps);
  233. }
  234. if (ps.Count > 2 && !includeLastPoint)
  235. {
  236. MapPoint p0 = ps[0];
  237. MapPoint pn = ps[ps.Count - 1];
  238. if (p0.X == pn.X && p0.Y == pn.Y)
  239. {
  240. first.Attributes.Add("lastPnt", pn);
  241. }
  242. }
  243. if (includeLastPoint)
  244. {
  245. Graphic g = AddVertexToEditLayer(graphic, vertexLayer, ps[ps.Count - 1]);
  246. g.Attributes.Add("PointCollection", ps);
  247. }
  248. }
  249. private void AddHoverLineSegment(PointCollection ps, MapPoint p0, MapPoint p1, Graphic graphic)
  250. {
  251. Polyline linesegment = new Polyline();
  252. linesegment.Paths.Add(new PointCollection());
  253. linesegment.Paths[0].Add(p0);
  254. linesegment.Paths[0].Add(p1);
  255. Graphic segment = new Graphic() { Geometry = linesegment, Symbol = hoverLine };
  256. segment.SetZIndex(1);
  257. vertexLayer.Graphics.Add(segment);
  258. segment.Attributes.Add("PointCollection", ps);
  259. segment.Attributes.Add("Feature", graphic);
  260. }
  261. /// <summary>
  262. ///Removes the snap vertex.
  263. /// </summary>
  264. /// <param name="sender">The sender.</param>
  265. /// <param name="graphic">The graphic.</param>
  266. /// <param name="args">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
  267. private void vertexLayer_MouseLeave(object sender, Graphic graphic, MouseEventArgs args)
  268. {
  269. if (snapVertex != null)
  270. {
  271. vertexLayer.Graphics.Remove(snapVertex);
  272. snapVertex = null;
  273. }
  274. }
  275. /// <summary>
  276. /// Shows and moves the snap vertex.
  277. /// </summary>
  278. /// <param name="sender">The sender.</param>
  279. /// <param name="graphic">The graphic.</param>
  280. /// <param name="args">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
  281. private void vertexLayer_MouseMove(object sender, Graphic graphic, MouseEventArgs args)
  282. {
  283. if (DraggingVertex != null) return;
  284. if (graphic.Geometry is Polyline) //We are over a hover line
  285. {
  286. Polyline line = graphic.Geometry as Polyline;
  287. Point pScreen = args.GetPosition(MyMap);
  288. MapPoint pMap = MyMap.ScreenToMap(pScreen);
  289. MapPoint snap = FindPointOnLineClosestToPoint(line.Paths[0][0], line.Paths[0][1], pMap);
  290. if (snapVertex == null)
  291. {
  292. snapVertex = new Graphic() { Symbol = snapSymbol, Geometry = snap };
  293. vertexLayer.Graphics.Add(snapVertex);
  294. }
  295. else
  296. {
  297. snapVertex.Geometry = snap;
  298. }
  299. }
  300. }
  301. /// <summary>
  302. /// Finds the point on a line closest to point (used for line snapping).
  303. /// </summary>
  304. /// <param name="p0">Start of line segment.</param>
  305. /// <param name="p1">End of line segment.</param>
  306. /// <param name="p">Point to snap.</param>
  307. /// <returns></returns>
  308. private MapPoint FindPointOnLineClosestToPoint(MapPoint p0, MapPoint p1, MapPoint p)
  309. {
  310. MapPoint p0p = new MapPoint(p.X - p0.X, p.Y - p0.Y);
  311. MapPoint p1p = new MapPoint(p1.X - p0.X, p1.Y - p0.Y);
  312. double p0p1sq = p1p.X * p1p.X + p1p.Y * p1p.Y;
  313. double p0p_p0p1 = p0p.X * p1p.X + p0p.Y * p1p.Y;
  314. double t = p0p_p0p1 / p0p1sq;
  315. if (t < 0.0) t = 0.0;
  316. else if (t > 1.0) t = 1.0;
  317. return new MapPoint(p0.X + p1p.X * t, p0.Y + p1p.Y * t);
  318. }
  319. private Graphic AddVertexToEditLayer(Graphic graphic, GraphicsLayer layer, MapPoint p)
  320. {
  321. Graphic g = new Graphic()
  322. {
  323. Geometry = p,
  324. Symbol = VertexSymbol
  325. };
  326. g.SetZIndex(2);
  327. layer.Graphics.Add(g);
  328. g.Attributes.Add("Feature", graphic);
  329. g.AddDoubleClick(vertex_doubleClick);
  330. return g;
  331. }
  332. /// <summary>
  333. /// Handles the Double click event extension on Graphic and deletes the vertex.
  334. /// </summary>
  335. /// <param name="sender">The source of the event.</param>
  336. /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
  337. private void vertex_doubleClick(object sender, MouseButtonEventArgs e)
  338. {
  339. Graphic g = sender as Graphic;
  340.             Graphic parent = g.Attributes["Feature"] as Graphic;
  341.             if (parent.Geometry is Envelope) return; //Cannot delete
  342.             PointCollection p = g.Attributes["PointCollection"] as PointCollection;
  343. if (parent.Geometry is Polygon && p.Count < 5) return; //Cannot delete
  344. if (parent.Geometry is Polyline && p.Count < 3) return; //Cannot delete
  345. int index = p.IndexOf(g.Geometry as MapPoint);
  346. if (parent.Geometry is Polygon && index == 0) //Maintain closing point
  347. {
  348. p.RemoveAt(p.Count - 1); //remove last point
  349. p.Add(new MapPoint(p[1].X, p[1].Y)); //close poly
  350. }
  351. MapPoint removeItem = p[index];
  352. p.RemoveAt(index);
  353. //Restart edit to rebuild vertices and hover lines
  354. StopEdit(true);
  355. StartEdit(parent, true);
  356. OnGeometryEdit(g, null, removeItem, Action.VertexRemoved);
  357. }
  358. private MapPoint fromPoint;
  359. private void vertexLayer_MouseLeftButtonDown(object sender, Graphic graphic, MouseButtonEventArgs args)
  360. {
  361. if (graphic.Geometry is MapPoint) //Moving point
  362. {
  363. DraggingVertex = graphic;
  364. args.Handled = true; //Prevent map from reacting to mouse event
  365. DraggingVertex.Select();
  366. StartTracking();
  367. fromPoint = new MapPoint((graphic.Geometry as MapPoint).X, (graphic.Geometry as MapPoint).Y);
  368. }
  369. else if (graphic.Geometry is Polyline) //Adding vertex
  370. {
  371. Polyline line = graphic.Geometry as Polyline;
  372. Point pScreen = args.GetPosition(MyMap);
  373. MapPoint pMap = MyMap.ScreenToMap(pScreen);
  374. MapPoint snap = FindPointOnLineClosestToPoint(line.Paths[0][0], line.Paths[0][1], pMap);
  375. args.Handled = true;
  376. PointCollection pnts = graphic.Attributes["PointCollection"] as PointCollection;
  377. Graphic parent = graphic.Attributes["Feature"] as Graphic;
  378. //Add new vertex and immediately start tracking it
  379. if (snapVertex != null)
  380. vertexLayer.Graphics.Remove(snapVertex);
  381. DraggingVertex = AddVertexToEditLayer(parent, vertexLayer, snap);
  382. DraggingVertex.Select();
  383. args.Handled = true; //Prevent map from reacting to mouse event
  384. StartTracking();
  385. DraggingVertex.Attributes.Add("PointCollection", pnts);
  386. int index = pnts.IndexOf(line.Paths[0][0]);
  387. pnts.Insert(index + 1, snap);
  388. vertexLayer.Graphics.Remove(graphic);
  389. AddHoverLineSegment(pnts, line.Paths[0][0], snap, parent);
  390. AddHoverLineSegment(pnts, snap, line.Paths[0][1], parent);
  391. OnGeometryEdit(graphic, snap, null, Action.VertexAdded);
  392. fromPoint = new MapPoint(snap.X, snap.Y);
  393. }
  394. }
  395. /// <summary>
  396. /// Hooks up mouse events for moving the geometry/vertex
  397. /// </summary>
  398. private void StartTracking()
  399. {
  400. MyMap.MouseMove += Map_MouseMove;
  401. MyMap.MouseLeftButtonUp += Map_MouseLeftButtonUp;
  402. MyMap.MouseLeave += MyMap_MouseLeave;
  403. MyMap.KeyDown += MyMap_KeyDown;
  404. MyMap.Cursor = Cursors.None;
  405. MyMap.Focus();
  406. }
  407. private void MyMap_KeyDown(object sender, KeyEventArgs e)
  408. {
  409. //if (e.Key == Key.Delete && DraggingVertex != null && activeGraphic != null)
  410. //{
  411. //    if (activeGraphic.Geometry is MapPoint)
  412. //    {
  413. //        this.editLayer.Graphics.Remove(activeGraphic);
  414. //        StopTracking();
  415. //    }
  416. //    else
  417. //    {
  418. //        PointCollection coll = DraggingVertex.Attributes["PointCollection"] as PointCollection;
  419. //        coll.Remove(DraggingVertex.Geometry as MapPoint);
  420. //    }
  421. //    vertexLayer.Graphics.Remove(DraggingVertex);
  422. //    DraggingVertex = null;
  423. //}
  424. }
  425. /// <summary>
  426. /// Unhooks mouse events and stops tracking vertex dragging
  427. /// </summary>
  428. private void StopTracking()
  429. {
  430. MyMap.MouseLeave -= MyMap_MouseLeave;
  431. MyMap.MouseMove -= Map_MouseMove;
  432. MyMap.MouseLeftButtonUp -= Map_MouseLeftButtonUp;
  433. MyMap.KeyDown -= MyMap_KeyDown;
  434. MyMap.Cursor = Cursors.Arrow;
  435. fromPoint = null;
  436. if (DraggingVertex == null) return;
  437. //DraggingVertex.Symbol = VertexSymbol;
  438. DraggingVertex.UnSelect();
  439. DraggingVertex = null;
  440. if (activeGraphic != null && activeGraphic.Geometry is MapPoint)
  441. {
  442. StopEdit();
  443. }
  444. }
  445. /// <summary>
  446. /// Handles the MouseLeave event of the MyMap control (cancels vertex drag tracking).
  447. /// </summary>
  448. /// <param name="sender">The source of the event.</param>
  449. /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
  450. private void MyMap_MouseLeave(object sender, MouseEventArgs e)
  451. {
  452. StopTracking();
  453. }
  454. /// <summary>
  455. /// Handles the MouseLeftButtonUp event of the Map control (cancels vertex drag tracking).
  456. /// </summary>
  457. /// <param name="sender">The source of the event.</param>
  458. /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
  459. private void Map_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  460. {
  461. if (activeGraphic != null && DraggingVertex != null &&
  462. fromPoint!=null && (fromPoint.X != (DraggingVertex.Geometry as MapPoint).X || 
  463. fromPoint.Y != (DraggingVertex.Geometry as MapPoint).Y))
  464. OnGeometryEdit(activeGraphic, DraggingVertex.Geometry as MapPoint, fromPoint, Action.VextedMoved);
  465. StopTracking();
  466. }
  467. /// <summary>
  468. /// Handles the MouseMove event of the Map control.
  469. /// </summary>
  470. /// <param name="sender">The source of the event.</param>
  471. /// <param name="e">The <see cref="System.Windows.Input.MouseEventArgs"/> instance containing the event data.</param>
  472. private void Map_MouseMove(object sender, MouseEventArgs e)
  473. {
  474. if (DraggingVertex == null ||
  475. DraggingVertex.Geometry == null ||
  476. !(DraggingVertex.Geometry is MapPoint)) return;
  477. //Update the point geometry based on the map coordinate
  478. Point p = e.GetPosition(MyMap);
  479. ESRI.ArcGIS.Client.Geometry.MapPoint pnt = MyMap.ScreenToMap(p);
  480. MapPoint pEdit = DraggingVertex.Geometry as MapPoint;
  481. pEdit.X = pnt.X;
  482. pEdit.Y = pnt.Y;
  483. if (DraggingVertex.Attributes.ContainsKey("lastPnt")) //Polygon first vertex - also update closing vertex
  484. {
  485. pEdit = DraggingVertex.Attributes["lastPnt"] as MapPoint;
  486. pEdit.X = pnt.X;
  487. pEdit.Y = pnt.Y;
  488. }
  489.             else if (DraggingVertex.Attributes.ContainsKey("corner")) //Envelope
  490.             {
  491. Graphic g = DraggingVertex.Attributes["Feature"] as Graphic;
  492. Envelope env = g.Geometry as Envelope;
  493. if ((int)DraggingVertex.Attributes["corner"] == 0) //lower left
  494. {
  495. env.XMin = pnt.X;
  496. env.YMin = pnt.Y;
  497. }
  498. else //upper right
  499. {
  500. env.XMax = pnt.X;
  501. env.YMax = pnt.Y;
  502. }
  503.             }
  504. }
  505. protected void OnGeometryEdit(Graphic g, MapPoint newItem, MapPoint oldItem, Action action)
  506. {
  507. if (GeometryEdit != null)
  508. GeometryEdit(this, new GeometryEditEventArgs(g, newItem, oldItem, action));
  509. }
  510. }
  511. /// <summary>
  512. /// Extension method for tracking double clicking on graphics
  513. /// </summary>
  514. internal static class MouseExtensions
  515. {
  516. private const int doubleClickInterval = 200;
  517. private static readonly DependencyProperty DoubleClickTimerProperty = DependencyProperty.RegisterAttached("DoubleClickTimer", typeof(DispatcherTimer), typeof(UIElement), null);
  518. private static readonly DependencyProperty DoubleClickHandlersProperty = DependencyProperty.RegisterAttached("DoubleClickHandlers", typeof(List<MouseButtonEventHandler>), typeof(UIElement), null);
  519. private static readonly DependencyProperty DoubleClickPositionProperty = DependencyProperty.RegisterAttached("DoubleClickPosition", typeof(Point), typeof(UIElement), null);
  520. /// <summary>
  521. /// Adds a double click event handler.
  522. /// </summary>
  523. /// <param name="element">The Element to listen for double clicks on.</param>
  524. /// <param name="handler">The handler.</param>
  525. public static void AddDoubleClick(this Graphic element, MouseButtonEventHandler handler)
  526. {
  527. element.MouseLeftButtonDown += element_MouseLeftButtonDown;
  528. List<MouseButtonEventHandler> handlers;
  529. handlers = element.GetValue(DoubleClickHandlersProperty) as List<MouseButtonEventHandler>;
  530. if (handlers == null)
  531. {
  532. handlers = new List<MouseButtonEventHandler>();
  533. element.SetValue(DoubleClickHandlersProperty, handlers);
  534. }
  535. handlers.Add(handler);
  536. }
  537. /// <summary>
  538. /// Removes a double click event handler.
  539. /// </summary>
  540. /// <param name="element">The element.</param>
  541. /// <param name="handler">The handler.</param>
  542. public static void RemoveDoubleClick(this Graphic element, MouseButtonEventHandler handler)
  543. {
  544. element.MouseLeftButtonDown -= element_MouseLeftButtonDown;
  545. List<MouseButtonEventHandler> handlers = element.GetValue(DoubleClickHandlersProperty) as List<MouseButtonEventHandler>;
  546. if (handlers != null)
  547. {
  548. handlers.Remove(handler);
  549. if (handlers.Count == 0)
  550. element.ClearValue(DoubleClickHandlersProperty);
  551. }
  552. }
  553. private static void element_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  554. {
  555. Graphic element = sender as Graphic;
  556. Point position = e.GetPosition(Application.Current.RootVisual);
  557. DispatcherTimer timer = element.GetValue(DoubleClickTimerProperty) as DispatcherTimer;
  558. if (timer != null) //DblClick
  559. {
  560. timer.Stop();
  561. Point oldPosition = (Point)element.GetValue(DoubleClickPositionProperty);
  562. element.ClearValue(DoubleClickTimerProperty);
  563. element.ClearValue(DoubleClickPositionProperty);
  564. if (Math.Abs(oldPosition.X - position.X) < 1 && Math.Abs(oldPosition.Y - position.Y) < 1) //mouse didn't move => Valid double click
  565. {
  566. List<MouseButtonEventHandler> handlers = element.GetValue(DoubleClickHandlersProperty) as List<MouseButtonEventHandler>;
  567. if (handlers != null)
  568. {
  569. foreach (MouseButtonEventHandler handler in handlers)
  570. {
  571. handler(sender, e);
  572. }
  573. }
  574. return;
  575. }
  576. }
  577. //First click or mouse moved. Start a new timer
  578. timer = new DispatcherTimer() { Interval = TimeSpan.FromMilliseconds(doubleClickInterval) };
  579. timer.Tick += new EventHandler((s, args) =>
  580. {  //DblClick timed out
  581. (s as DispatcherTimer).Stop();
  582. element.ClearValue(DoubleClickTimerProperty); //clear timer
  583. element.ClearValue(DoubleClickPositionProperty); //clear first click position
  584. });
  585. element.SetValue(DoubleClickTimerProperty, timer);
  586. element.SetValue(DoubleClickPositionProperty, position);
  587. timer.Start();
  588. }
  589. }
  590. }