ImageView.xaml.cs 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260
  1. using System;
  2. using System.Windows;
  3. using System.Windows.Controls;
  4. using System.Windows.Input;
  5. using System.Windows.Shapes;
  6. using TeamAAS_VP.ViewModels;
  7. namespace TeamAAS_VP.Views
  8. {
  9. public partial class ImageView : UserControl
  10. {
  11. private Point _start;
  12. private Shape _previewShape;
  13. private bool _isDown;
  14. private UIElement _dragTarget;
  15. private Point _dragOffset;
  16. // 新增:记录当前选中的批注元素
  17. private UIElement _selectedAnnotation;
  18. public ImageView()
  19. {
  20. InitializeComponent();
  21. Loaded += ImageView_Loaded;
  22. }
  23. private void ImageView_Loaded(object sender, RoutedEventArgs e)
  24. {
  25. var vm = DataContext as ImageViewModel;
  26. vm?.AttachRenderTarget(RootPixelRender, AnnoCanvas);
  27. vm?.LoadLast();
  28. // 让 KeyDown 可用
  29. AnnoCanvas.Focus();
  30. }
  31. private ImageViewModel Vm => DataContext as ImageViewModel;
  32. private Point GetPixelPoint(MouseEventArgs e)
  33. {
  34. var p = e.GetPosition(AnnoCanvas);
  35. var vm = Vm;
  36. if (vm == null || vm.PixelWidth <= 0 || vm.PixelHeight <= 0)
  37. {
  38. return p;
  39. }
  40. var actualW = AnnoCanvas.ActualWidth;
  41. var actualH = AnnoCanvas.ActualHeight;
  42. if (actualW <= 0 || actualH <= 0) return p;
  43. var scaleX = actualW / vm.PixelWidth;
  44. var scaleY = actualH / vm.PixelHeight;
  45. if (scaleX <= 0) scaleX = 1;
  46. if (scaleY <= 0) scaleY = 1;
  47. return new Point(p.X / scaleX, p.Y / scaleY);
  48. }
  49. private UIElement GetAnnotationElementFromOriginalSource(object originalSource)
  50. {
  51. // 右键/左键命中的可能是:Rectangle/TextBlock/Grid/Line/Polygon 等子元素
  52. var element = originalSource as DependencyObject;
  53. while (element != null)
  54. {
  55. if (element is Rectangle) return (UIElement)element;
  56. if (element is TextBlock) return (UIElement)element;
  57. if (element is Grid) return (UIElement)element;
  58. // 命中箭头内部:Line/Polygon -> 往上找 Grid
  59. element = System.Windows.Media.VisualTreeHelper.GetParent(element);
  60. }
  61. return null;
  62. }
  63. private void SelectAnnotation(UIElement element)
  64. {
  65. _selectedAnnotation = element;
  66. // 简单选中效果(可选):给选中项加虚线描边
  67. // 只处理 Rectangle / Grid(箭头) 的视觉效果;TextBlock 不做边框避免影响显示
  68. foreach (var child in AnnoCanvas.Children)
  69. {
  70. if (child is Rectangle rr)
  71. {
  72. rr.StrokeDashArray = null;
  73. }
  74. }
  75. if (_selectedAnnotation is Rectangle r)
  76. {
  77. r.StrokeDashArray = new System.Windows.Media.DoubleCollection() { 2, 2 };
  78. }
  79. }
  80. private void DeleteSelectedAnnotation()
  81. {
  82. if (Vm == null) return;
  83. if (_selectedAnnotation == null) return;
  84. Vm.RemoveAnnotation(_selectedAnnotation);
  85. _selectedAnnotation = null;
  86. }
  87. private void AnnoCanvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
  88. {
  89. if (Vm == null) return;
  90. var hit = GetAnnotationElementFromOriginalSource(e.OriginalSource);
  91. if (hit == null || hit == AnnoCanvas)
  92. {
  93. _selectedAnnotation = null;
  94. return;
  95. }
  96. SelectAnnotation(hit);
  97. AnnoCanvas.Focus();
  98. var menu = new ContextMenu();
  99. var deleteItem = new MenuItem() { Header = "删除" };
  100. deleteItem.Click += (s, ev) => DeleteSelectedAnnotation();
  101. menu.Items.Add(deleteItem);
  102. // 打开菜单
  103. menu.PlacementTarget = AnnoCanvas;
  104. menu.IsOpen = true;
  105. e.Handled = true;
  106. }
  107. private void AnnoCanvas_KeyDown(object sender, KeyEventArgs e)
  108. {
  109. if (e.Key == Key.Delete)
  110. {
  111. DeleteSelectedAnnotation();
  112. e.Handled = true;
  113. }
  114. }
  115. private void AnnoCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
  116. {
  117. if (Vm == null) return;
  118. _isDown = true;
  119. _start = GetPixelPoint(e);
  120. AnnoCanvas.CaptureMouse();
  121. // Select 模式:左键点中即选中
  122. if (Vm.Tool == "Select")
  123. {
  124. var hit = GetAnnotationElementFromOriginalSource(e.OriginalSource);
  125. if (hit != null && hit != AnnoCanvas)
  126. {
  127. SelectAnnotation(hit);
  128. _dragTarget = hit;
  129. var p = _start;
  130. var left = Canvas.GetLeft(_dragTarget);
  131. var top = Canvas.GetTop(_dragTarget);
  132. if (double.IsNaN(left)) left = 0;
  133. if (double.IsNaN(top)) top = 0;
  134. _dragOffset = new Point(p.X - left, p.Y - top);
  135. }
  136. else
  137. {
  138. _selectedAnnotation = null;
  139. _dragTarget = null;
  140. }
  141. return;
  142. }
  143. if (Vm.Tool == "Rect")
  144. {
  145. var rect = Vm.CreateRect();
  146. Canvas.SetLeft(rect, _start.X);
  147. Canvas.SetTop(rect, _start.Y);
  148. rect.Width = 1;
  149. rect.Height = 1;
  150. _previewShape = rect;
  151. AnnoCanvas.Children.Add(rect);
  152. return;
  153. }
  154. if (Vm.Tool == "Arrow")
  155. {
  156. var g = Vm.CreateArrowGroup(_start, _start);
  157. AnnoCanvas.Children.Add(g);
  158. _previewShape = g.Tag as Shape;
  159. return;
  160. }
  161. if (Vm.Tool == "Text")
  162. {
  163. Vm.CreateTextAt(AnnoCanvas, _start);
  164. _isDown = false;
  165. AnnoCanvas.ReleaseMouseCapture();
  166. }
  167. }
  168. private void AnnoCanvas_MouseMove(object sender, MouseEventArgs e)
  169. {
  170. if (!_isDown || Vm == null) return;
  171. var p = GetPixelPoint(e);
  172. if (Vm.Tool == "Select")
  173. {
  174. if (_dragTarget != null && _dragTarget != AnnoCanvas && e.LeftButton == MouseButtonState.Pressed)
  175. {
  176. Canvas.SetLeft(_dragTarget, p.X - _dragOffset.X);
  177. Canvas.SetTop(_dragTarget, p.Y - _dragOffset.Y);
  178. }
  179. return;
  180. }
  181. if (Vm.Tool == "Rect" && _previewShape is Rectangle r)
  182. {
  183. var x = Math.Min(p.X, _start.X);
  184. var y = Math.Min(p.Y, _start.Y);
  185. var w = Math.Abs(p.X - _start.X);
  186. var h = Math.Abs(p.Y - _start.Y);
  187. Canvas.SetLeft(r, x);
  188. Canvas.SetTop(r, y);
  189. r.Width = Math.Max(1, w);
  190. r.Height = Math.Max(1, h);
  191. return;
  192. }
  193. if (Vm.Tool == "Arrow")
  194. {
  195. Vm.UpdateLastArrow(AnnoCanvas, p);
  196. }
  197. }
  198. private void AnnoCanvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
  199. {
  200. if (Vm == null) return;
  201. _isDown = false;
  202. AnnoCanvas.ReleaseMouseCapture();
  203. var p = GetPixelPoint(e);
  204. if (Vm.Tool == "Arrow")
  205. {
  206. Vm.CommitLastArrow(AnnoCanvas, p);
  207. }
  208. _previewShape = null;
  209. _dragTarget = null;
  210. }
  211. }
  212. }