Files
XplorePlane/XP.ImageProcessing.RoiControl/Controls/PolygonRoiCanvas.xaml.cs
T

775 lines
28 KiB
C#

using XP.ImageProcessing.RoiControl.Models;
using System;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace XP.ImageProcessing.RoiControl.Controls
{
public partial class PolygonRoiCanvas : UserControl
{
private bool isDragging = false;
private Point lastMousePosition;
private const double ZoomStep = 1.2;
private Adorner? currentAdorner;
public PolygonRoiCanvas()
{
InitializeComponent();
Loaded += PolygonRoiCanvas_Loaded;
}
private void PolygonRoiCanvas_Loaded(object sender, RoutedEventArgs e)
{
// 监听ROI集合变化
if (ROIItems != null)
{
ROIItems.CollectionChanged += ROIItems_CollectionChanged;
foreach (var roi in ROIItems)
{
roi.PropertyChanged += ROI_PropertyChanged;
// 如果是多边形ROI,监听Points集合变化
if (roi is PolygonROI polygonROI)
{
polygonROI.Points.CollectionChanged += Points_CollectionChanged;
}
}
}
}
private void ROIItems_CollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null)
{
foreach (ROIShape roi in e.NewItems)
{
roi.PropertyChanged += ROI_PropertyChanged;
// 如果是多边形ROI,监听Points集合变化
if (roi is PolygonROI polygonROI)
{
polygonROI.Points.CollectionChanged += Points_CollectionChanged;
}
}
}
if (e.OldItems != null)
{
foreach (ROIShape roi in e.OldItems)
{
roi.PropertyChanged -= ROI_PropertyChanged;
// 取消监听Points集合变化
if (roi is PolygonROI polygonROI)
{
polygonROI.Points.CollectionChanged -= Points_CollectionChanged;
}
}
}
}
private void Points_CollectionChanged(object? sender, System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
// 只在删除或添加顶点时更新Adorner,拖拽时的Replace操作不触发更新
if (e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Remove ||
e.Action == System.Collections.Specialized.NotifyCollectionChangedAction.Add)
{
// Points集合变化时,如果当前选中的是多边形ROI,更新Adorner
if (SelectedROI is PolygonROI polygonROI && sender == polygonROI.Points)
{
// 使用Dispatcher延迟更新,确保UI已经处理完Points的变化
Dispatcher.BeginInvoke(new Action(() =>
{
UpdateAdorner();
}), System.Windows.Threading.DispatcherPriority.Render);
}
}
// Replace操作(拖拽时)不需要重建Adorner,只需要让现有Adorner重新布局
}
private void ROI_PropertyChanged(object? sender, System.ComponentModel.PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(ROIShape.IsSelected))
{
UpdateAdorner();
}
// 监听Points属性变化(整个集合替换的情况)
else if (e.PropertyName == "Points" && sender is PolygonROI)
{
UpdateAdorner();
}
}
#region Dependency Properties
public static readonly DependencyProperty ImageSourceProperty =
DependencyProperty.Register(nameof(ImageSource), typeof(ImageSource), typeof(PolygonRoiCanvas),
new PropertyMetadata(null, OnImageSourceChanged));
public ImageSource? ImageSource
{
get => (ImageSource?)GetValue(ImageSourceProperty);
set => SetValue(ImageSourceProperty, value);
}
private static void OnImageSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (PolygonRoiCanvas)d;
if (e.NewValue is BitmapSource bitmap)
{
// 使用像素尺寸,避免 DPI 不同导致 DIP 尺寸与实际像素不一致
control.CanvasWidth = bitmap.PixelWidth;
control.CanvasHeight = bitmap.PixelHeight;
control.ResetView();
}
else if (e.NewValue is ImageSource imageSource)
{
control.CanvasWidth = imageSource.Width;
control.CanvasHeight = imageSource.Height;
control.ResetView();
}
}
public static readonly DependencyProperty ROIItemsProperty =
DependencyProperty.Register(nameof(ROIItems), typeof(ObservableCollection<ROIShape>), typeof(PolygonRoiCanvas),
new PropertyMetadata(null));
public ObservableCollection<ROIShape>? ROIItems
{
get => (ObservableCollection<ROIShape>?)GetValue(ROIItemsProperty);
set => SetValue(ROIItemsProperty, value);
}
public static readonly DependencyProperty ZoomScaleProperty =
DependencyProperty.Register(nameof(ZoomScale), typeof(double), typeof(PolygonRoiCanvas),
new PropertyMetadata(1.0, OnZoomScaleChanged));
public double ZoomScale
{
get => (double)GetValue(ZoomScaleProperty);
set => SetValue(ZoomScaleProperty, Math.Max(0.1, Math.Min(10.0, value)));
}
private static void OnZoomScaleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (PolygonRoiCanvas)d;
// 缩放变化时更新Adorner以调整控制点大小
control.UpdateAdorner();
}
public static readonly DependencyProperty PanOffsetXProperty =
DependencyProperty.Register(nameof(PanOffsetX), typeof(double), typeof(PolygonRoiCanvas),
new PropertyMetadata(0.0, OnPanOffsetChanged));
public double PanOffsetX
{
get => (double)GetValue(PanOffsetXProperty);
set => SetValue(PanOffsetXProperty, value);
}
public static readonly DependencyProperty PanOffsetYProperty =
DependencyProperty.Register(nameof(PanOffsetY), typeof(double), typeof(PolygonRoiCanvas),
new PropertyMetadata(0.0, OnPanOffsetChanged));
public double PanOffsetY
{
get => (double)GetValue(PanOffsetYProperty);
set => SetValue(PanOffsetYProperty, value);
}
private static void OnPanOffsetChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (PolygonRoiCanvas)d;
// 平移时重建Adorner,确保控制点位置正确
if (control.SelectedROI != null && control.SelectedROI.IsSelected)
{
control.UpdateAdorner();
}
}
public static readonly DependencyProperty CanvasWidthProperty =
DependencyProperty.Register(nameof(CanvasWidth), typeof(double), typeof(PolygonRoiCanvas),
new PropertyMetadata(800.0));
public double CanvasWidth
{
get => (double)GetValue(CanvasWidthProperty);
set => SetValue(CanvasWidthProperty, value);
}
public static readonly DependencyProperty CanvasHeightProperty =
DependencyProperty.Register(nameof(CanvasHeight), typeof(double), typeof(PolygonRoiCanvas),
new PropertyMetadata(600.0));
public double CanvasHeight
{
get => (double)GetValue(CanvasHeightProperty);
set => SetValue(CanvasHeightProperty, value);
}
public static readonly DependencyProperty SelectedROIProperty =
DependencyProperty.Register(nameof(SelectedROI), typeof(ROIShape), typeof(PolygonRoiCanvas),
new PropertyMetadata(null, OnSelectedROIChanged));
public ROIShape? SelectedROI
{
get => (ROIShape?)GetValue(SelectedROIProperty);
set => SetValue(SelectedROIProperty, value);
}
private static void OnSelectedROIChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = (PolygonRoiCanvas)d;
// 更新IsSelected状态
if (e.OldValue is ROIShape oldROI)
{
oldROI.IsSelected = false;
}
if (e.NewValue is ROIShape newROI)
{
newROI.IsSelected = true;
}
control.UpdateAdorner();
}
#endregion Dependency Properties
#region Crosshair
public static readonly DependencyProperty ShowCrosshairProperty =
DependencyProperty.Register(nameof(ShowCrosshair), typeof(bool), typeof(PolygonRoiCanvas),
new PropertyMetadata(false, OnShowCrosshairChanged));
public bool ShowCrosshair
{
get => (bool)GetValue(ShowCrosshairProperty);
set => SetValue(ShowCrosshairProperty, value);
}
private Line _crosshairH, _crosshairV;
private static void OnShowCrosshairChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var c = (PolygonRoiCanvas)d;
if ((bool)e.NewValue)
c.AddCrosshair();
else
c.RemoveCrosshair();
}
private void AddCrosshair()
{
RemoveCrosshair();
double w = CanvasWidth, h = CanvasHeight;
if (w <= 0 || h <= 0) return;
_crosshairH = new Line { X1 = 0, Y1 = h / 2, X2 = w, Y2 = h / 2, Stroke = Brushes.Red, StrokeThickness = 1, Opacity = 0.7, IsHitTestVisible = false };
_crosshairV = new Line { X1 = w / 2, Y1 = 0, X2 = w / 2, Y2 = h, Stroke = Brushes.Red, StrokeThickness = 1, Opacity = 0.7, IsHitTestVisible = false };
mainCanvas.Children.Add(_crosshairH);
mainCanvas.Children.Add(_crosshairV);
}
private void RemoveCrosshair()
{
if (_crosshairH != null) { mainCanvas.Children.Remove(_crosshairH); _crosshairH = null; }
if (_crosshairV != null) { mainCanvas.Children.Remove(_crosshairV); _crosshairV = null; }
}
#endregion Crosshair
#region Measurement
public static readonly DependencyProperty IsMeasuringProperty =
DependencyProperty.Register(nameof(IsMeasuring), typeof(bool), typeof(PolygonRoiCanvas),
new PropertyMetadata(false, OnIsMeasuringChanged));
public bool IsMeasuring
{
get => (bool)GetValue(IsMeasuringProperty);
set => SetValue(IsMeasuringProperty, value);
}
private Canvas _measureOverlay;
private readonly System.Collections.Generic.List<Models.MeasureGroup> _measureGroups = new();
private Ellipse _pendingDot;
private Point? _pendingPoint;
private Ellipse _mDraggingDot;
private Models.MeasureGroup _mDraggingGroup;
private bool _mDraggingIsDot1;
private static void OnIsMeasuringChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var c = (PolygonRoiCanvas)d;
if ((bool)e.NewValue)
{
c.EnsureMeasureOverlay();
}
else
{
// 退出测量模式:只清除未完成的临时点,保留已完成的测量线
if (c._pendingDot != null && c._measureOverlay != null)
{
c._measureOverlay.Children.Remove(c._pendingDot);
c._pendingDot = null;
}
c._pendingPoint = null;
}
}
private void EnsureMeasureOverlay()
{
if (_measureOverlay != null) return;
_measureOverlay = new Canvas { IsHitTestVisible = true, Background = Brushes.Transparent };
_measureOverlay.SetBinding(Canvas.WidthProperty, new System.Windows.Data.Binding("CanvasWidth") { Source = this });
_measureOverlay.SetBinding(Canvas.HeightProperty, new System.Windows.Data.Binding("CanvasHeight") { Source = this });
mainCanvas.Children.Add(_measureOverlay);
}
private void RemoveMeasureOverlay()
{
if (_measureOverlay != null)
{
mainCanvas.Children.Remove(_measureOverlay);
_measureOverlay = null;
}
_measureGroups.Clear();
_pendingDot = null;
_pendingPoint = null;
_mDraggingDot = null;
_mDraggingGroup = null;
}
/// <summary>清除所有测量绘制</summary>
public void ClearMeasurements()
{
RemoveMeasureOverlay();
}
/// <summary>获取当前测量组数量</summary>
public int MeasureCount => _measureGroups.Count;
/// <summary>处理测量模式下的画布点击</summary>
private void HandleMeasureClick(Point pos)
{
if (_measureOverlay == null) EnsureMeasureOverlay();
if (_measureOverlay == null) return;
if (!_pendingPoint.HasValue)
{
_pendingPoint = pos;
_pendingDot = CreateMeasureDot(Brushes.Red);
_measureOverlay.Children.Add(_pendingDot);
SetMeasureDotPos(_pendingDot, pos);
RaiseMeasureStatusChanged($"点点距测量 - 第一点: ({pos.X:F0}, {pos.Y:F0}),请点击第二个点");
}
else
{
var g = CreateMeasureGroup(_pendingPoint.Value, pos);
_measureGroups.Add(g);
_measureOverlay.Children.Remove(_pendingDot);
_pendingDot = null;
_pendingPoint = null;
RaiseMeasureCompleted(g);
// 完成一条测量后自动退出测量模式
IsMeasuring = false;
}
}
private Models.MeasureGroup CreateMeasureGroup(Point p1, Point p2)
{
var g = new Models.MeasureGroup { P1 = p1, P2 = p2 };
g.Line = new Line { Stroke = Brushes.Lime, StrokeThickness = 2, IsHitTestVisible = false };
_measureOverlay.Children.Add(g.Line);
g.Label = new TextBlock { Foreground = Brushes.Yellow, FontSize = 13, FontWeight = FontWeights.Bold, IsHitTestVisible = false };
_measureOverlay.Children.Add(g.Label);
g.Dot1 = CreateMeasureDot(Brushes.Red);
g.Dot2 = CreateMeasureDot(Brushes.Blue);
_measureOverlay.Children.Add(g.Dot1);
_measureOverlay.Children.Add(g.Dot2);
SetMeasureDotPos(g.Dot1, p1);
SetMeasureDotPos(g.Dot2, p2);
g.UpdateLine();
g.UpdateLabel();
return g;
}
private Ellipse CreateMeasureDot(Brush fill)
{
var dot = new Ellipse { Width = 12, Height = 12, Fill = fill, Stroke = Brushes.White, StrokeThickness = 1.5, Cursor = Cursors.Hand };
dot.SetValue(ContextMenuService.IsEnabledProperty, false);
dot.MouseLeftButtonDown += MDot_Down;
dot.MouseMove += MDot_Move;
dot.MouseLeftButtonUp += MDot_Up;
dot.PreviewMouseRightButtonUp += MDot_RightClick;
return dot;
}
private static void SetMeasureDotPos(Ellipse dot, Point pos)
{
Canvas.SetLeft(dot, pos.X - dot.Width / 2);
Canvas.SetTop(dot, pos.Y - dot.Height / 2);
}
private void MDot_Down(object sender, MouseButtonEventArgs e)
{
if (sender is not Ellipse dot) return;
foreach (var g in _measureGroups)
{
if (g.Dot1 == dot) { _mDraggingGroup = g; _mDraggingIsDot1 = true; break; }
if (g.Dot2 == dot) { _mDraggingGroup = g; _mDraggingIsDot1 = false; break; }
}
if (_mDraggingGroup != null) { _mDraggingDot = dot; dot.CaptureMouse(); e.Handled = true; }
}
private void MDot_Move(object sender, MouseEventArgs e)
{
if (_mDraggingDot == null || _mDraggingGroup == null || _measureOverlay == null) return;
if (e.LeftButton != MouseButtonState.Pressed) return;
var pos = e.GetPosition(_measureOverlay);
SetMeasureDotPos(_mDraggingDot, pos);
if (_mDraggingIsDot1) _mDraggingGroup.P1 = pos; else _mDraggingGroup.P2 = pos;
_mDraggingGroup.UpdateLine();
_mDraggingGroup.UpdateLabel();
RaiseMeasureCompleted(_mDraggingGroup);
e.Handled = true;
}
private void MDot_Up(object sender, MouseButtonEventArgs e)
{
if (_mDraggingDot != null) { _mDraggingDot.ReleaseMouseCapture(); _mDraggingDot = null; _mDraggingGroup = null; e.Handled = true; }
}
private void MDot_RightClick(object sender, MouseButtonEventArgs e)
{
if (sender is not Ellipse dot || _measureOverlay == null) return;
Models.MeasureGroup target = null;
foreach (var g in _measureGroups)
{
if (g.Dot1 == dot || g.Dot2 == dot) { target = g; break; }
}
if (target == null) return;
_measureOverlay.Children.Remove(target.Dot1);
_measureOverlay.Children.Remove(target.Dot2);
_measureOverlay.Children.Remove(target.Line);
_measureOverlay.Children.Remove(target.Label);
_measureGroups.Remove(target);
RaiseMeasureStatusChanged($"已删除测量线 | 剩余 {_measureGroups.Count} 条");
e.Handled = true;
}
// 测量事件
public static readonly RoutedEvent MeasureCompletedEvent =
EventManager.RegisterRoutedEvent(nameof(MeasureCompleted), RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(PolygonRoiCanvas));
public event RoutedEventHandler MeasureCompleted
{
add { AddHandler(MeasureCompletedEvent, value); }
remove { RemoveHandler(MeasureCompletedEvent, value); }
}
private void RaiseMeasureCompleted(Models.MeasureGroup g)
{
RaiseEvent(new MeasureCompletedEventArgs(MeasureCompletedEvent, g.P1, g.P2, g.Distance, _measureGroups.Count));
}
public static readonly RoutedEvent MeasureStatusChangedEvent =
EventManager.RegisterRoutedEvent(nameof(MeasureStatusChanged), RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(PolygonRoiCanvas));
public event RoutedEventHandler MeasureStatusChanged
{
add { AddHandler(MeasureStatusChangedEvent, value); }
remove { RemoveHandler(MeasureStatusChangedEvent, value); }
}
private void RaiseMeasureStatusChanged(string message)
{
RaiseEvent(new MeasureStatusEventArgs(MeasureStatusChangedEvent, message));
}
#endregion Measurement
#region Adorner Management
private void UpdateAdorner()
{
// 移除旧的Adorner
if (currentAdorner != null)
{
var adornerLayer = AdornerLayer.GetAdornerLayer(mainCanvas);
if (adornerLayer != null)
{
adornerLayer.Remove(currentAdorner);
}
currentAdorner = null;
}
// 为选中的ROI添加Adorner
if (SelectedROI != null && SelectedROI.IsSelected)
{
// 查找对应的UI元素
var container = FindROIVisual(SelectedROI);
if (container != null)
{
var adornerLayer = AdornerLayer.GetAdornerLayer(mainCanvas);
if (adornerLayer != null)
{
double scaleFactor = 1.0 / ZoomScale;
if (SelectedROI is PolygonROI polygonROI)
{
currentAdorner = new PolygonAdorner(container, scaleFactor, polygonROI);
}
if (currentAdorner != null)
{
adornerLayer.Add(currentAdorner);
}
}
}
}
}
private UIElement? FindROIVisual(ROIShape roi)
{
// 在ItemsControl中查找对应的视觉元素
var itemsControl = FindVisualChild<ItemsControl>(mainCanvas);
if (itemsControl != null)
{
for (int i = 0; i < itemsControl.Items.Count; i++)
{
if (itemsControl.Items[i] == roi)
{
// 尝试获取容器
var container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as ContentPresenter;
// 如果容器还没生成,尝试强制生成
if (container == null)
{
// 强制生成容器
itemsControl.UpdateLayout();
container = itemsControl.ItemContainerGenerator.ContainerFromIndex(i) as ContentPresenter;
}
if (container != null)
{
// 查找实际的形状元素(只支持多边形)
if (roi is PolygonROI)
{
return FindVisualChild<Polygon>(container);
}
}
}
}
}
return null;
}
private T? FindVisualChild<T>(DependencyObject parent) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = VisualTreeHelper.GetChild(parent, i);
if (child is T result)
{
return result;
}
var childOfChild = FindVisualChild<T>(child);
if (childOfChild != null)
{
return childOfChild;
}
}
return null;
}
#endregion Adorner Management
#region Mouse Events
private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
{
double oldZoom = ZoomScale;
double newZoom = e.Delta > 0 ? oldZoom * ZoomStep : oldZoom / ZoomStep;
newZoom = Math.Max(0.1, Math.Min(10.0, newZoom));
if (Math.Abs(newZoom - oldZoom) > 0.001)
{
ZoomScale = newZoom;
// RenderTransformOrigin="0.5,0.5" 保证以图像中心等比缩放
// 拖拽平移偏移保持不变
}
e.Handled = true;
}
private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
lastMousePosition = e.GetPosition(imageDisplayGrid);
isDragging = false;
mainCanvas.CaptureMouse();
}
private void Canvas_MouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed && mainCanvas.IsMouseCaptured)
{
Point currentPosition = e.GetPosition(imageDisplayGrid);
Vector delta = currentPosition - lastMousePosition;
if (delta.Length > 5)
{
isDragging = true;
PanOffsetX += delta.X;
PanOffsetY += delta.Y;
lastMousePosition = currentPosition;
}
}
}
private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
mainCanvas.ReleaseMouseCapture();
if (!isDragging)
{
Point clickPosition = e.GetPosition(mainCanvas);
if (IsMeasuring)
HandleMeasureClick(clickPosition);
OnCanvasClicked(clickPosition);
}
isDragging = false;
}
private void Canvas_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
{
// 右键点击完成多边形
OnRightClick();
// 不设 e.Handled,让 ContextMenu 正常弹出
}
private void ROI_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
// 选择ROI
if (sender is FrameworkElement element && element.DataContext is ROIShape roi)
{
SelectedROI = roi;
e.Handled = true;
}
}
#endregion Mouse Events
#region Public Methods
public void ResetView()
{
PanOffsetX = 0;
PanOffsetY = 0;
if (imageDisplayGrid == null || CanvasWidth <= 0 || CanvasHeight <= 0)
{
ZoomScale = 1.0;
return;
}
// 延迟到布局完成后计算,确保 ActualWidth/Height 准确
Dispatcher.BeginInvoke(new Action(() =>
{
double viewW = imageDisplayGrid.ActualWidth;
double viewH = imageDisplayGrid.ActualHeight;
if (viewW > 0 && viewH > 0)
{
ZoomScale = Math.Min(viewW / CanvasWidth, viewH / CanvasHeight);
}
else
{
ZoomScale = 1.0;
}
PanOffsetX = 0;
PanOffsetY = 0;
}), System.Windows.Threading.DispatcherPriority.Render);
}
private void BtnZoomIn_Click(object sender, RoutedEventArgs e)
{
double newZoom = ZoomScale * 1.2;
if (newZoom <= 10.0)
{
ZoomScale = newZoom;
PanOffsetX = 0;
PanOffsetY = 0;
}
}
private void BtnZoomOut_Click(object sender, RoutedEventArgs e)
{
double newZoom = ZoomScale / 1.2;
if (newZoom >= 0.1)
{
ZoomScale = newZoom;
PanOffsetX = 0;
PanOffsetY = 0;
}
}
private void BtnReset_Click(object sender, RoutedEventArgs e)
{
ResetView();
}
#endregion Public Methods
#region Events
public static readonly RoutedEvent CanvasClickedEvent =
EventManager.RegisterRoutedEvent(nameof(CanvasClicked), RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(PolygonRoiCanvas));
public event RoutedEventHandler CanvasClicked
{
add { AddHandler(CanvasClickedEvent, value); }
remove { RemoveHandler(CanvasClickedEvent, value); }
}
protected virtual void OnCanvasClicked(Point position)
{
var args = new CanvasClickedEventArgs(CanvasClickedEvent, position);
RaiseEvent(args);
}
public static readonly RoutedEvent RightClickEvent =
EventManager.RegisterRoutedEvent(nameof(RightClick), RoutingStrategy.Bubble,
typeof(RoutedEventHandler), typeof(PolygonRoiCanvas));
public event RoutedEventHandler RightClick
{
add { AddHandler(RightClickEvent, value); }
remove { RemoveHandler(RightClickEvent, value); }
}
protected virtual void OnRightClick()
{
RaiseEvent(new RoutedEventArgs(RightClickEvent));
}
#endregion Events
}
}