ROIBox.cs:实现了一个 WPF 自定义控件 ROIBox(Region of Interest Box),用于在图像上绘制可交互的矩形区域(ROI),支持拖动、调整大小等操作 ROIBox.cs实现了一个 WPF 自定义控件 ROIBoxRegion of Interest Box用于在图像上绘制可交互的矩形区域ROI支持拖动、调整大小等操作using ROIControl.Drawings;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;using System.Windows;using System.Windows.Input;using System.Windows.Media;namespace ROIControl{public class ROIBoxCommands{publicstaticRoutedUICommand ClearRectnewRoutedUICommand(){Text清除};}public class ROIBox:FrameworkElement{staticROIBox(){DefaultStyleKeyProperty.OverrideMetadata(typeof(ROIBox),newFrameworkPropertyMetadata(typeof(ROIBox)));}private VisualCollection _visualCollection;private ImageDrawingVisual _imageDrawingVisualnewImageDrawingVisual();private RectDrawingVisual _rectDrawingVisual;private IState _currentState;publicROIBox(){this._currentStatenewDefaultRectState(this);this._visualCollectionnewVisualCollection(this);this._rectDrawingVisualnewRectDrawingVisual(this);this._visualCollection.Add(_imageDrawingVisual);this._visualCollection.Add(_rectDrawingVisual);this.MouseDownthis.ROIBox_MouseDown;this.MouseMovethis.ROIBox_MouseMove;this.MouseUpthis.ROIBox_MouseUp;this.MouseLeavethis.ROIBox_MouseLeave;this.CommandBindings.Add(newCommandBinding(ROIBoxCommands.ClearRect,(s,e){this.RectRect.Empty;}));this.Loadedthis.ROIBox_Loaded;}privatevoidROIBox_Loaded(object sender,RoutedEventArgs e){this.UpdateImage();this.UpdateRect();}privatevoidROIBox_MouseLeave(object sender,System.Windows.Input.MouseEventArgs e){_currentState?.MouseLeave(sender,e);}privatevoidROIBox_MouseUp(object sender,System.Windows.Input.MouseButtonEventArgs e){_currentState?.MouseUp(sender,e);}privatevoidROIBox_MouseMove(object sender,System.Windows.Input.MouseEventArgs e){_currentState?.MouseMove(sender,e);}privatevoidROIBox_MouseDown(object sender,System.Windows.Input.MouseButtonEventArgs e){_currentState?.MouseDown(sender,e);e.Handledtrue;}#region-VisualCollection-protected override VisualGetVisualChild(intindex){return_visualCollection[index];}protected overrideintVisualChildrenCount{get{return_visualCollection.Count;}}#endregionpublic ImageSource ImageSource{get{return(ImageSource)GetValue(ImageSourceProperty);}set{SetValue(ImageSourceProperty,value);}}publicstaticreadonly DependencyProperty ImageSourcePropertyDependencyProperty.Register(ImageSource,typeof(ImageSource),typeof(ROIBox),newFrameworkPropertyMetadata(default(ImageSource),(d,e){ROIBox controld as ROIBox;if(controlnull)return;if(e.OldValue is ImageSource o){}if(e.NewValue is ImageSource n){}control.UpdateImage();}));privatevoidUpdateImage(){this.Widththis.ImageSource?.Width??0;this.Heightthis.ImageSource?.Height??0;this._imageDrawingVisual.ImageSourcethis.ImageSource;}public bool IsRectValid!this.Rect.IsEmpty;public Rect BoundingBox{get{if(this.ImageSourcenull)returnRect.Empty;returnnewRect(0,0,this.ImageSource.Width,this.ImageSource.Height);}}public Rect Rect{get{return(Rect)GetValue(RectProperty);}set{SetValue(RectProperty,value);}}publicstaticreadonly DependencyProperty RectPropertyDependencyProperty.Register(Rect,typeof(Rect),typeof(ROIBox),newFrameworkPropertyMetadata(default(Rect),(d,e){ROIBox controld as ROIBox;if(controlnull)return;if(e.OldValue is Rect o){}if(e.NewValue is Rect n){}control.UpdateRect();}));publicdoubleHandleLength{get{return(double)GetValue(HandleLengthProperty);}set{SetValue(HandleLengthProperty,value);}}publicstaticreadonly DependencyProperty HandleLengthPropertyDependencyProperty.Register(HandleLength,typeof(double),typeof(ROIBox),newFrameworkPropertyMetadata(6.0,(d,e){ROIBox controld as ROIBox;if(controlnull)return;if(e.OldValue isdoubleo){}if(e.NewValue isdoublen){}control.UpdateRect();}));public Brush Stroke{get{return(Brush)GetValue(StrokeProperty);}set{SetValue(StrokeProperty,value);}}publicstaticreadonly DependencyProperty StrokePropertyDependencyProperty.Register(Stroke,typeof(Brush),typeof(ROIBox),newFrameworkPropertyMetadata(Brushes.Chartreuse,(d,e){ROIBox controld as ROIBox;if(controlnull)return;if(e.OldValue is Brush o){}if(e.NewValue is Brush n){}control.UpdateRect();}));publicdoubleStrokeThickness{get{return(double)GetValue(StrokeThicknessProperty);}set{SetValue(StrokeThicknessProperty,value);}}publicstaticreadonly DependencyProperty StrokeThicknessPropertyDependencyProperty.Register(StrokeThickness,typeof(double),typeof(ROIBox),newFrameworkPropertyMetadata(1.0,(d,e){ROIBox controld as ROIBox;if(controlnull)return;if(e.OldValue isdoubleo){}if(e.NewValue isdoublen){}control.UpdateRect();}));public Brush Fill{get{return(Brush)GetValue(FillProperty);}set{SetValue(FillProperty,value);}}publicstaticreadonly DependencyProperty FillPropertyDependencyProperty.Register(Fill,typeof(Brush),typeof(ROIBox),newFrameworkPropertyMetadata(newSolidColorBrush(Colors.Black){Opacity0.8},(d,e){ROIBox controld as ROIBox;if(controlnull)return;if(e.OldValue is Brush o){}if(e.NewValue is Brush n){}control.UpdateRect();}));public bool UseCross{get{return(bool)GetValue(UseCrossProperty);}set{SetValue(UseCrossProperty,value);}}publicstaticreadonly DependencyProperty UseCrossPropertyDependencyProperty.Register(UseCross,typeof(bool),typeof(ROIBox),newFrameworkPropertyMetadata(true,(d,e){ROIBox controld as ROIBox;if(controlnull)return;if(e.OldValue is bool o){}if(e.NewValue is bool n){}control.UpdateRect();}));privatevoidUpdateRect(){this._rectDrawingVisual.Strokethis.Stroke;this._rectDrawingVisual.StrokeThicknessthis.StrokeThickness;this._rectDrawingVisual.HandleLengththis.HandleLength;this._rectDrawingVisual.Fillthis.Fill;this._rectDrawingVisual.Rectthis.Rect;this._rectDrawingVisual.Draw();}}}