IState 接口详解 - 状态核心接口这是状态机系统中最基础、最核心的接口定义了所有状态必须实现的鼠标事件处理方法。它是整个状态机架构的基石所有具体状态绘制、选择、编辑等都直接或间接遵循这个契约。 文件头部和命名空间// 版权信息同前// Copyright (c) HeBianGu Authors. All Rights Reserved.// ...省略usingSystem.Windows.Input;// 导入鼠标输入相关类型MouseEventArgs、MouseButtonEventArgs等namespaceH.LabelImg.ShapeBox.State.Base;// 命名空间存放形状状态机相关的基础类 IState 接口// 接口定义所有状态必须实现的核心接口// 这个接口定义了状态与用户交互的基本能力publicinterfaceIState{// 修饰键属性 // 指定激活此状态需要按下的修饰键Ctrl、Alt、Shift等// 例如// - ModifierKeys.None - 不需要修饰键直接激活// - ModifierKeys.Control - 需要按住 Ctrl 键才能激活// - ModifierKeys.Shift - 需要按住 Shift 键才能激活// - ModifierKeys.Alt - 需要按住 Alt 键才能激活ModifierKeysModifierKeys{get;set;}// 鼠标按下事件 // 当用户在控件上按下鼠标按钮时触发// 参数// sender - 事件发送者通常是 ShapeBox 控件// e - 鼠标事件参数包含按下的按钮、点击次数、位置等voidMouseDown(objectsender,MouseButtonEventArgse);// 鼠标离开事件 // 当鼠标离开控件区域时触发// 参数// sender - 事件发送者// e - 鼠标事件参数voidMouseLeave(objectsender,MouseEventArgse);// 鼠标移动事件 // 当鼠标在控件上移动时触发// 参数// sender - 事件发送者// e - 鼠标事件参数包含鼠标当前位置voidMouseMove(objectsender,MouseEventArgse);// 鼠标释放事件 // 当用户在控件上释放鼠标按钮时触发// 参数// sender - 事件发送者// e - 鼠标事件参数voidMouseUp(objectsender,MouseButtonEventArgse);} 设计目的为什么需要 IState 接口这个接口为状态机系统提供了统一的交互契约// 没有接口的情况无法统一处理publicclassRectState{publicvoidOnMouseDown(...){}// 方法名不同publicvoidOnMouseMove(...){}// 签名可能不一致}publicclassCircleState{publicvoidHandleMouseDown(...){}// 完全不同的命名}// 有 IState 接口统一处理publicclassRectState:IState{publicvoidMouseDown(...){}// 标准命名publicvoidMouseMove(...){}}publicclassCircleState:IState{publicvoidMouseDown(...){}// 相同签名publicvoidMouseMove(...){}} 接口方法详解1. ModifierKeys 属性ModifierKeysModifierKeys{get;set;}作用控制状态激活的条件// 示例只有在按住 Ctrl 时才激活此状态publicclassZoomState:IState{publicModifierKeysModifierKeys{get;set;}ModifierKeys.Control;publicvoidMouseMove(objectsender,MouseEventArgse){// 只有在按住 Ctrl 时才会执行到这里// 执行缩放逻辑...}}ModifierKeys 枚举值值说明典型用途None无修饰键普通绘制、选择ControlCtrl 键缩放、多选ShiftShift 键约束比例、追加选择AltAlt 键辅助功能、临时切换2. MouseDown 方法voidMouseDown(objectsender,MouseButtonEventArgse);典型实现publicvoidMouseDown(objectsender,MouseButtonEventArgse){if(e.ChangedButtonMouseButton.Left){// 左键开始绘制StartDrawing(e.GetPosition(senderasFrameworkElement));}elseif(e.ChangedButtonMouseButton.Right){// 右键取消操作Cancel();}}3. MouseMove 方法voidMouseMove(objectsender,MouseEventArgse);典型实现publicvoidMouseMove(objectsender,MouseEventArgse){if(_isDrawing){// 更新预览形状UpdatePreview(e.GetPosition(senderasFrameworkElement));}}4. MouseUp 方法voidMouseUp(objectsender,MouseButtonEventArgse);典型实现publicvoidMouseUp(objectsender,MouseButtonEventArgse){if(_isDrawinge.ChangedButtonMouseButton.Left){// 完成绘制CompleteDrawing();}}5. MouseLeave 方法voidMouseLeave(objectsender,MouseEventArgse);典型实现publicvoidMouseLeave(objectsender,MouseEventArgse){// 清除预览ClearPreview();} 完整实现示例示例1简单绘制状态publicclassSimpleDrawState:IState{privatebool_isDrawing;privatePoint_startPoint;privateIShapeView_view;publicModifierKeysModifierKeys{get;set;}ModifierKeys.None;publicSimpleDrawState(IShapeViewview){_viewview;}publicvoidMouseDown(objectsender,MouseButtonEventArgse){if(e.ChangedButtonMouseButton.Left){_isDrawingtrue;_startPointe.GetPosition(senderasFrameworkElement);}}publicvoidMouseMove(objectsender,MouseEventArgse){if(_isDrawing){varcurrente.GetPosition(senderasFrameworkElement);// 更新预览...}}publicvoidMouseUp(objectsender,MouseButtonEventArgse){if(_isDrawinge.ChangedButtonMouseButton.Left){varendPointe.GetPosition(senderasFrameworkElement);// 创建形状..._isDrawingfalse;}}publicvoidMouseLeave(objectsender,MouseEventArgse){_isDrawingfalse;}}示例2带修饰键的状态publicclassMultiSelectState:IState{privateISelectShapeBox_selectBox;privateRect_selectionRect;privatePoint_startPoint;privatebool_isSelecting;publicMultiSelectState(ISelectShapeBoxselectBox){_selectBoxselectBox;// 需要按住 Shift 才能多选this.ModifierKeysModifierKeys.Shift;}publicModifierKeysModifierKeys{get;set;}publicvoidMouseDown(objectsender,MouseButtonEventArgse){if(e.ChangedButtonMouseButton.Left){_isSelectingtrue;_startPointe.GetPosition(senderasFrameworkElement);_selectionRectnewRect(_startPoint,_startPoint);}}publicvoidMouseMove(objectsender,MouseEventArgse){if(_isSelecting){varcurrente.GetPosition(senderasFrameworkElement);_selectionRectnewRect(_startPoint,current);// 更新选择框预览...}}publicvoidMouseUp(objectsender,MouseButtonEventArgse){if(_isSelecting){// 选择框内的所有形状SelectShapesInRect(_selectionRect);_isSelectingfalse;}}publicvoidMouseLeave(objectsender,MouseEventArgse){_isSelectingfalse;}privatevoidSelectShapesInRect(Rectrect){// 选择框选中的形状...}}示例3临时状态切换publicclassTemporaryZoomState:IState{privateStateShapeBox_box;privatedouble_originalScale;privatePoint_center;publicTemporaryZoomState(StateShapeBoxbox){_boxbox;// 按住 Alt 时临时激活缩放this.ModifierKeysModifierKeys.Alt;}publicModifierKeysModifierKeys{get;set;}publicvoidMouseDown(objectsender,MouseButtonEventArgse){if(e.ChangedButtonMouseButton.Left){_originalScale_box.Scale;_centere.GetPosition(senderasFrameworkElement);}}publicvoidMouseMove(objectsender,MouseEventArgse){if(e.LeftButtonMouseButtonState.Pressed){varcurrente.GetPosition(senderasFrameworkElement);doubledelta(current.Y-_center.Y)/100;_box.Scale_originalScale*(1delta);}}publicvoidMouseUp(objectsender,MouseButtonEventArgse){// 恢复原始缩放或保持}publicvoidMouseLeave(objectsender,MouseEventArgse){// 离开时恢复_box.Scale_originalScale;}} 在状态机中的使用publicclassStateShapeBox:ShapeBox{privateIState_currentState;publicIStateCurrentState{get_currentState;set_currentStatevalue;}protectedoverridevoidOnMouseDown(MouseButtonEventArgse){// 检查当前状态的修饰键要求if(_currentState?.ModifierKeysKeyboard.Modifiers){_currentState.MouseDown(this,e);if(e.Handled)return;}base.OnMouseDown(e);}protectedoverridevoidOnMouseMove(MouseEventArgse){if(_currentState?.ModifierKeysKeyboard.Modifiers){_currentState.MouseMove(this,e);if(e.Handled)return;}base.OnMouseMove(e);}protectedoverridevoidOnMouseUp(MouseButtonEventArgse){if(_currentState?.ModifierKeysKeyboard.Modifiers){_currentState.MouseUp(this,e);if(e.Handled)return;}base.OnMouseUp(e);}protectedoverridevoidOnMouseLeave(MouseEventArgse){_currentState?.MouseLeave(this,e);base.OnMouseLeave(e);}} 接口层次结构IState核心接口← 当前接口 ↓ IViewState扩展接口 ↓ StateBase抽象基类 ↓ ShapeStyleSettingStateBase ↓ ShowEditStateBase ↓ PreviewShapeStateBase ↓ HandleShapeStateBase ↓ ShapeStateT ↓ AddShapeStateT ↓ OneClickAddShapeStateT ↓ TwoClickAddShapeStateT ↓ AddRectShapeState设计模式分析1. 命令模式鼠标事件被封装为接口方法不同状态实现不同的命令逻辑。2. 策略模式通过接口实现不同的交互策略可以在运行时切换。3. 观察者模式状态作为鼠标事件的观察者响应并处理事件。4. 接口隔离原则接口只包含必要的方法不包含无关内容。总结成员类型用途ModifierKeys属性激活状态需要的修饰键MouseDown()方法处理鼠标按下MouseMove()方法处理鼠标移动MouseUp()方法处理鼠标释放MouseLeave()方法处理鼠标离开核心价值统一契约所有状态遵循相同的接口修饰键支持可以指定激活条件完整事件覆盖所有鼠标交互可扩展可以添加更多事件方法典型应用✅ 绘制状态处理拖拽绘制✅ 选择状态处理点击选择✅ 编辑状态处理控制点拖拽✅ 缩放状态处理缩放操作这个接口是整个状态机系统的根基为所有交互状态提供了统一的规范