优化虚拟摇杆运动控制界面显示问题,将generic修改为usercontrol,单轴摇杆修改为腰圆形状,将功能增加至主框架程序。

This commit is contained in:
QI Mingxuan
2026-04-22 22:49:46 +08:00
parent be03bdf34e
commit 461294986e
10 changed files with 400 additions and 857 deletions
@@ -293,12 +293,12 @@ Confirm to filll move matrix?</value>
<value>Calibration Value</value>
</data>
<data name="AC_Enable" xml:space="preserve">
<value>Enable</value>
<value>Physical Joystick Enable</value>
</data>
<data name="AC_Save" xml:space="preserve">
<value>Save</value>
<value>Save Position</value>
</data>
<data name="AC_Restore" xml:space="preserve">
<value>Restore</value>
<value>Restore Position</value>
</data>
</root>
@@ -347,15 +347,15 @@ DetectorZ → {4:F2}mm
<comment>校准自动计算值标签 | Calibration value label</comment>
</data>
<data name="AC_Enable" xml:space="preserve">
<value>使能</value>
<value>实体操作摇杆使能</value>
<comment>使能开关标签 | Enable toggle label</comment>
</data>
<data name="AC_Save" xml:space="preserve">
<value>保存</value>
<value>保存当前位置</value>
<comment>保存按钮文本 | Save button text</comment>
</data>
<data name="AC_Restore" xml:space="preserve">
<value>恢复</value>
<value>恢复前一位置</value>
<comment>恢复按钮文本 | Restore button text</comment>
</data>
</root>
@@ -293,12 +293,12 @@ DetectorZ → {4:F2}mm
<value>校准计算值</value>
</data>
<data name="AC_Enable" xml:space="preserve">
<value>使能</value>
<value>实体操作摇杆使能</value>
</data>
<data name="AC_Save" xml:space="preserve">
<value>保存</value>
<value>保存当前位置</value>
</data>
<data name="AC_Restore" xml:space="preserve">
<value>恢复</value>
<value>恢复前一位置</value>
</data>
</root>
@@ -293,12 +293,12 @@ DetectorZ → {4:F2}mm
<value>校準計算值</value>
</data>
<data name="AC_Enable" xml:space="preserve">
<value>使能</value>
<value>實體操作搖桿使能</value>
</data>
<data name="AC_Save" xml:space="preserve">
<value>保存</value>
<value>保存當前位置</value>
</data>
<data name="AC_Restore" xml:space="preserve">
<value>恢復</value>
<value>恢復前一位置</value>
</data>
</root>
@@ -9,146 +9,148 @@
xmlns:controls="clr-namespace:XP.Common.Controls;assembly=XP.Common"
prism:ViewModelLocator.AutoWireViewModel="True"
mc:Ignorable="d"
MinWidth="350"
HorizontalAlignment="Stretch" Background="White">
<Grid Margin="8">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid Margin="6">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- ========== 左侧区域:轴位置 + 安全参数 | Left: Axis Positions + Safety Params ========== -->
<StackPanel Grid.Column="0" Margin="0,0,8,0">
<!-- ========== 上部:左(轴位置+ 右(摇杆)========== -->
<Grid Grid.Row="0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<!-- 轴位置输入框组 | Axis Position Inputs -->
<GroupBox Margin="0,0,0,6">
<GroupBox.Header>
<TextBlock Text="{loc:Localization AC_AxisPositions}" FontWeight="Bold" FontSize="12"/>
</GroupBox.Header>
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="80"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- ===== 左侧:轴位置输入框 ===== -->
<Grid Grid.Column="0" Margin="0,0,4,0" VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="60"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- Stage X -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="{loc:Localization AC_StageX}"
FontSize="12" VerticalAlignment="Center" Margin="0,2"/>
<telerik:RadNumericUpDown Grid.Row="0" Grid.Column="1" x:Name="NumStageX"
Value="{Binding StageXPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
GotFocus="NumStageX_GotFocus" LostFocus="NumStageX_LostFocus" KeyDown="NumStageX_KeyDown"
Margin="4,2" telerik:StyleManager.Theme="Crystal"/>
<TextBlock Grid.Row="0" Grid.Column="0" Text="{loc:Localization AC_StageX}" FontSize="11" VerticalAlignment="Center" Margin="0,1,4,1"/>
<telerik:RadNumericUpDown Grid.Row="0" Grid.Column="1" x:Name="NumStageX" Value="{Binding StageXPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ValueFormat="Numeric" NumberDecimalDigits="1" SmallChange="0.1" IsEditable="True" GotFocus="NumStageX_GotFocus" LostFocus="NumStageX_LostFocus" KeyDown="NumStageX_KeyDown" Margin="0,1" Height="24" FontSize="11" telerik:StyleManager.Theme="Crystal"/>
<!-- Stage Y -->
<TextBlock Grid.Row="1" Grid.Column="0" Text="{loc:Localization AC_StageY}"
FontSize="12" VerticalAlignment="Center" Margin="0,2"/>
<telerik:RadNumericUpDown Grid.Row="1" Grid.Column="1" x:Name="NumStageY"
Value="{Binding StageYPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
GotFocus="NumStageY_GotFocus" LostFocus="NumStageY_LostFocus" KeyDown="NumStageY_KeyDown"
Margin="4,2" telerik:StyleManager.Theme="Crystal"/>
<TextBlock Grid.Row="1" Grid.Column="0" Text="{loc:Localization AC_StageY}" FontSize="11" VerticalAlignment="Center" Margin="0,1,4,1"/>
<telerik:RadNumericUpDown Grid.Row="1" Grid.Column="1" x:Name="NumStageY" Value="{Binding StageYPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ValueFormat="Numeric" NumberDecimalDigits="1" SmallChange="0.1" IsEditable="True" GotFocus="NumStageY_GotFocus" LostFocus="NumStageY_LostFocus" KeyDown="NumStageY_KeyDown" Margin="0,1" Height="24" FontSize="11" telerik:StyleManager.Theme="Crystal"/>
<!-- Source Z -->
<TextBlock Grid.Row="2" Grid.Column="0" Text="{loc:Localization AC_SourceZ}"
FontSize="12" VerticalAlignment="Center" Margin="0,2"/>
<telerik:RadNumericUpDown Grid.Row="2" Grid.Column="1" x:Name="NumSourceZ"
Value="{Binding SourceZPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
GotFocus="NumSourceZ_GotFocus" LostFocus="NumSourceZ_LostFocus" KeyDown="NumSourceZ_KeyDown"
Margin="4,2" telerik:StyleManager.Theme="Crystal"/>
<TextBlock Grid.Row="2" Grid.Column="0" Text="{loc:Localization AC_SourceZ}" FontSize="11" VerticalAlignment="Center" Margin="0,1,4,1"/>
<telerik:RadNumericUpDown Grid.Row="2" Grid.Column="1" x:Name="NumSourceZ" Value="{Binding SourceZPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ValueFormat="Numeric" NumberDecimalDigits="1" SmallChange="0.1" IsEditable="True" GotFocus="NumSourceZ_GotFocus" LostFocus="NumSourceZ_LostFocus" KeyDown="NumSourceZ_KeyDown" Margin="0,1" Height="24" FontSize="11" telerik:StyleManager.Theme="Crystal"/>
<!-- Detector Z -->
<TextBlock Grid.Row="3" Grid.Column="0" Text="{loc:Localization AC_DetectorZ}"
FontSize="12" VerticalAlignment="Center" Margin="0,2"/>
<telerik:RadNumericUpDown Grid.Row="3" Grid.Column="1" x:Name="NumDetectorZ"
Value="{Binding DetectorZPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
GotFocus="NumDetectorZ_GotFocus" LostFocus="NumDetectorZ_LostFocus" KeyDown="NumDetectorZ_KeyDown"
Margin="4,2" telerik:StyleManager.Theme="Crystal"/>
<TextBlock Grid.Row="3" Grid.Column="0" Text="{loc:Localization AC_DetectorZ}" FontSize="11" VerticalAlignment="Center" Margin="0,1,4,1"/>
<telerik:RadNumericUpDown Grid.Row="3" Grid.Column="1" x:Name="NumDetectorZ" Value="{Binding DetectorZPosition, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ValueFormat="Numeric" NumberDecimalDigits="1" SmallChange="0.1" IsEditable="True" GotFocus="NumDetectorZ_GotFocus" LostFocus="NumDetectorZ_LostFocus" KeyDown="NumDetectorZ_KeyDown" Margin="0,1" Height="24" FontSize="11" telerik:StyleManager.Theme="Crystal"/>
<!-- Detector Swing(动态显示/隐藏)| Dynamic visibility -->
<TextBlock Grid.Row="4" Grid.Column="0" Text="{loc:Localization AC_DetectorSwing}"
FontSize="12" VerticalAlignment="Center" Margin="0,2"
Visibility="{Binding DetectorSwingVisibility}"/>
<telerik:RadNumericUpDown Grid.Row="4" Grid.Column="1" x:Name="NumDetSwing"
Value="{Binding DetectorSwingAngle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
GotFocus="NumDetSwing_GotFocus" LostFocus="NumDetSwing_LostFocus" KeyDown="NumDetSwing_KeyDown"
Visibility="{Binding DetectorSwingVisibility}"
Margin="4,2" telerik:StyleManager.Theme="Crystal"/>
<TextBlock Grid.Row="4" Grid.Column="0" Text="{loc:Localization AC_DetectorSwing}" FontSize="11" VerticalAlignment="Center" Margin="0,1,4,1" Visibility="{Binding DetectorSwingVisibility}"/>
<telerik:RadNumericUpDown Grid.Row="4" Grid.Column="1" x:Name="NumDetSwing" Value="{Binding DetectorSwingAngle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ValueFormat="Numeric" NumberDecimalDigits="1" SmallChange="0.1" IsEditable="True" GotFocus="NumDetSwing_GotFocus" LostFocus="NumDetSwing_LostFocus" KeyDown="NumDetSwing_KeyDown" Visibility="{Binding DetectorSwingVisibility}" Margin="0,1" Height="24" FontSize="11" telerik:StyleManager.Theme="Crystal"/>
<!-- Stage Rotation(动态显示/隐藏)| Dynamic visibility -->
<TextBlock Grid.Row="5" Grid.Column="0" Text="{loc:Localization AC_StageRotation}"
FontSize="12" VerticalAlignment="Center" Margin="0,2"
Visibility="{Binding StageRotationVisibility}"/>
<telerik:RadNumericUpDown Grid.Row="5" Grid.Column="1" x:Name="NumStageRot"
Value="{Binding StageRotationAngle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
GotFocus="NumStageRot_GotFocus" LostFocus="NumStageRot_LostFocus" KeyDown="NumStageRot_KeyDown"
Visibility="{Binding StageRotationVisibility}"
Margin="4,2" telerik:StyleManager.Theme="Crystal"/>
<TextBlock Grid.Row="5" Grid.Column="0" Text="{loc:Localization AC_StageRotation}" FontSize="11" VerticalAlignment="Center" Margin="0,1,4,1" Visibility="{Binding StageRotationVisibility}"/>
<telerik:RadNumericUpDown Grid.Row="5" Grid.Column="1" x:Name="NumStageRot" Value="{Binding StageRotationAngle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ValueFormat="Numeric" NumberDecimalDigits="1" SmallChange="0.1" IsEditable="True" GotFocus="NumStageRot_GotFocus" LostFocus="NumStageRot_LostFocus" KeyDown="NumStageRot_KeyDown" Visibility="{Binding StageRotationVisibility}" Margin="0,1" Height="24" FontSize="11" telerik:StyleManager.Theme="Crystal"/>
<!-- Fixture Rotation(动态显示/隐藏)| Dynamic visibility -->
<TextBlock Grid.Row="6" Grid.Column="0" Text="{loc:Localization AC_FixtureRotation}"
FontSize="12" VerticalAlignment="Center" Margin="0,2"
Visibility="{Binding FixtureRotationVisibility}"/>
<telerik:RadNumericUpDown Grid.Row="6" Grid.Column="1" x:Name="NumFixtureRot"
Value="{Binding FixtureRotationAngle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
GotFocus="NumFixtureRot_GotFocus" LostFocus="NumFixtureRot_LostFocus" KeyDown="NumFixtureRot_KeyDown"
Visibility="{Binding FixtureRotationVisibility}"
Margin="4,2" telerik:StyleManager.Theme="Crystal"/>
</Grid>
</GroupBox>
<TextBlock Grid.Row="6" Grid.Column="0" Text="{loc:Localization AC_FixtureRotation}" FontSize="11" VerticalAlignment="Center" Margin="0,1,4,1" Visibility="{Binding FixtureRotationVisibility}"/>
<telerik:RadNumericUpDown Grid.Row="6" Grid.Column="1" x:Name="NumFixtureRot" Value="{Binding FixtureRotationAngle, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" ValueFormat="Numeric" NumberDecimalDigits="1" SmallChange="0.1" IsEditable="True" GotFocus="NumFixtureRot_GotFocus" LostFocus="NumFixtureRot_LostFocus" KeyDown="NumFixtureRot_KeyDown" Visibility="{Binding FixtureRotationVisibility}" Margin="0,1" Height="24" FontSize="11" telerik:StyleManager.Theme="Crystal"/>
</Grid>
<!-- 安全参数输入框组 | Safety Parameter Inputs -->
<GroupBox Margin="0,0,0,6">
<GroupBox.Header>
<TextBlock Text="{loc:Localization AC_SafetyParams}" FontWeight="Bold" FontSize="12"/>
</GroupBox.Header>
<Grid Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" MinWidth="80"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- ===== 右侧:摇杆区域 ===== -->
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center"
Margin="4,12,4,12">
<!-- 单轴摇杆(腰圆)-->
<controls:VirtualJoystick x:Name="SingleJoystick"
JoystickMode="SingleAxisY"
Width="40" Height="160"
IsEnabled="{Binding IsJoystickEnabled}"
DefaultTopIcon="↑" DefaultBottomIcon="↓"
LeftButtonTopIcon="Src↑" LeftButtonBottomIcon="Src↓"
RightButtonTopIcon="Det↑" RightButtonBottomIcon="Det↓"
Margin="2,0,8,0"/>
<!-- 安全高度 | Safety Height -->
<TextBlock Grid.Row="0" Grid.Column="0" Text="{loc:Localization AC_SafetyHeight}"
FontSize="12" VerticalAlignment="Center" Margin="0,2"/>
<telerik:RadNumericUpDown Grid.Row="0" Grid.Column="1" x:Name="NumSafetyHeight"
Value="{Binding SafetyHeight, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
KeyDown="NumSafetyHeight_KeyDown"
Margin="4,2" telerik:StyleManager.Theme="Crystal"/>
<!-- 双轴摇杆(圆形)-->
<controls:VirtualJoystick x:Name="DualJoystick"
JoystickMode="DualAxis"
Width="160" Height="160"
IsEnabled="{Binding IsJoystickEnabled}"
DefaultTopIcon="↑" DefaultBottomIcon="" DefaultLeftIcon="←" DefaultRightIcon="→"
LeftButtonTopIcon="Y+" LeftButtonBottomIcon="Y-" LeftButtonLeftIcon="X-" LeftButtonRightIcon="X+"
RightButtonTopIcon="Rot+" RightButtonBottomIcon="Rot-" RightButtonLeftIcon="Swing-" RightButtonRightIcon="Swing+"
Margin="0,0,2,0"/>
</StackPanel>
</Grid>
<!-- 校准计算值 | Calibration Value -->
<TextBlock Grid.Row="1" Grid.Column="0" Text="{loc:Localization AC_CalibrationValue}"
FontSize="12" VerticalAlignment="Center" Margin="0,2"/>
<telerik:RadNumericUpDown Grid.Row="1" Grid.Column="1" x:Name="NumCalibration"
Value="{Binding CalibrationValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
KeyDown="NumCalibration_KeyDown"
Margin="4,2" telerik:StyleManager.Theme="Crystal"/>
</Grid>
</GroupBox>
<!-- ========== 下部:安全参数(一行均布)+ 操作按钮(一行均布)========== -->
<StackPanel Grid.Row="1" Margin="0,8,0,0">
<!-- 错误信息显示 | Error Message Display -->
<TextBlock Text="{Binding ErrorMessage}" FontSize="11" Foreground="#FFE53935"
TextWrapping="Wrap" Margin="0,2">
<!-- 安全参数一行(均布)-->
<Grid Margin="0,0,0,6">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="{loc:Localization AC_SafetyHeight}"
FontSize="11" VerticalAlignment="Center" Margin="0,0,4,0"/>
<telerik:RadNumericUpDown Grid.Column="1" x:Name="NumSafetyHeight"
Value="{Binding SafetyHeight, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
KeyDown="NumSafetyHeight_KeyDown"
Height="24" MinWidth="70" FontSize="11" telerik:StyleManager.Theme="Crystal"/>
<TextBlock Grid.Column="3" Text="{loc:Localization AC_CalibrationValue}"
FontSize="11" VerticalAlignment="Center" Margin="0,0,4,0"/>
<telerik:RadNumericUpDown Grid.Column="4" x:Name="NumCalibration"
Value="{Binding CalibrationValue, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
ValueFormat="Numeric" NumberDecimalDigits="2" SmallChange="0.1" IsEditable="True"
KeyDown="NumCalibration_KeyDown"
Height="24" MinWidth="70" FontSize="11" telerik:StyleManager.Theme="Crystal"/>
</Grid>
<!-- 操作按钮一行(均布)-->
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="16"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- 使能开关 -->
<TextBlock Grid.Column="0" Text="{loc:Localization AC_Enable}" FontSize="11" VerticalAlignment="Center" Margin="0,0,4,0"/>
<telerik:RadToggleSwitchButton Grid.Column="1" IsChecked="{Binding IsJoystickEnabled, Mode=TwoWay}"
Command="{Binding ToggleEnableCommand}"
telerik:StyleManager.Theme="Crystal"/>
<!-- 保存当前位置 -->
<telerik:RadButton Grid.Column="3" Content="{loc:Localization AC_Save}"
Command="{Binding SavePositionsCommand}"
Height="24" MinWidth="80" Padding="8,0" FontSize="11"
telerik:StyleManager.Theme="Crystal"/>
<!-- 恢复前一位置 -->
<telerik:RadButton Grid.Column="5" Content="{loc:Localization AC_Restore}"
Command="{Binding RestorePositionsCommand}"
Height="24" MinWidth="80" Padding="8,0" FontSize="11"
telerik:StyleManager.Theme="Crystal"/>
</Grid>
<!-- 错误信息 -->
<TextBlock Text="{Binding ErrorMessage}" FontSize="10" Foreground="#FFE53935"
TextWrapping="Wrap" Margin="0,4,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Visible"/>
@@ -164,74 +166,5 @@
</TextBlock.Style>
</TextBlock>
</StackPanel>
<!-- ========== 右侧区域:摇杆 + 操作按钮 | Right: Joysticks + Action Buttons ========== -->
<Grid Grid.Column="1">
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- 摇杆区域 | Joystick Area -->
<StackPanel Grid.Row="0" Orientation="Horizontal" HorizontalAlignment="Center" VerticalAlignment="Center">
<!-- 单轴摇杆(SingleAxisY):Source_Z / Detector_Z | Single-axis joystick -->
<controls:VirtualJoystick x:Name="SingleJoystick"
JoystickMode="SingleAxisY"
Width="150" Height="200"
IsEnabled="{Binding IsJoystickEnabled}"
DefaultTopIcon="↑" DefaultBottomIcon="↓"
LeftButtonTopIcon="Src↑" LeftButtonBottomIcon="Src↓"
RightButtonTopIcon="Det↑" RightButtonBottomIcon="Det↓"
Margin="0,0,16,0"/>
<!-- 双轴摇杆(DualAxis):Stage X/Y + Swing/Rotation | Dual-axis joystick -->
<controls:VirtualJoystick x:Name="DualJoystick"
JoystickMode="DualAxis"
Width="200" Height="200"
IsEnabled="{Binding IsJoystickEnabled}"
DefaultTopIcon="↑" DefaultBottomIcon="↓" DefaultLeftIcon="←" DefaultRightIcon="→"
LeftButtonTopIcon="Y+" LeftButtonBottomIcon="Y-" LeftButtonLeftIcon="X-" LeftButtonRightIcon="X+"
RightButtonTopIcon="Rot+" RightButtonBottomIcon="Rot-" RightButtonLeftIcon="Swing-" RightButtonRightIcon="Swing+"/>
</StackPanel>
<!-- 操作按钮区域 | Action Buttons Area -->
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Center" Margin="0,8,0,0">
<!-- 使能开关 | Enable Toggle -->
<StackPanel Orientation="Horizontal" VerticalAlignment="Center" Margin="0,0,12,0">
<TextBlock Text="{loc:Localization AC_Enable}" FontSize="12" VerticalAlignment="Center" Margin="0,0,6,0"/>
<telerik:RadToggleSwitchButton IsChecked="{Binding IsJoystickEnabled, Mode=TwoWay}"
Command="{Binding ToggleEnableCommand}"
telerik:StyleManager.Theme="Crystal"/>
</StackPanel>
<!-- 保存按钮 | Save Button -->
<telerik:RadButton Content="{loc:Localization AC_Save}"
Command="{Binding SavePositionsCommand}"
Width="70" Height="28" Margin="4,0" FontSize="12"
telerik:StyleManager.Theme="Crystal">
<telerik:RadButton.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="White"/>
<GradientStop Color="#FF62B8E0" Offset="1"/>
</LinearGradientBrush>
</telerik:RadButton.Background>
</telerik:RadButton>
<!-- 恢复按钮 | Restore Button -->
<telerik:RadButton Content="{loc:Localization AC_Restore}"
Command="{Binding RestorePositionsCommand}"
Width="70" Height="28" Margin="4,0" FontSize="12"
telerik:StyleManager.Theme="Crystal">
<telerik:RadButton.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="White"/>
<GradientStop Color="#FFFFD54F" Offset="1"/>
</LinearGradientBrush>
</telerik:RadButton.Background>
</telerik:RadButton>
</StackPanel>
</Grid>
</Grid>
</UserControl>