WPF开发经验-实现一种三轴机械手控件
一 引入
考虑实现一种三轴机器人控件。
三轴机器人用来将某种工件从一个位置运送到另一个位置。
其X轴为手臂轴,可以正向和反向运动,它处于末端,直接接触工件;
其T轴为旋转轴,可以对手臂进行旋转;
其Z轴为升降轴,可以对手臂和旋转部分进行升降。
二 RobotControl
定义出机器人的轴动作枚举,轴的动作分为回原点,正向运动,反向运动。
public enum WaferRobotZAction
{
Z_Origin,
Z_CW,
Z_CCW
} public enum WaferRobotXAction
{
X_Origin,
X_CW,
X_CCW
} public enum WaferRobotTAction
{
T_Origin,
T_CW,
T_CCW
}
声明一个WaferRobotControl的自定义控件,它继承自Control类。
定义一个Wafer属性来表示WaferRobot上的工件。
定义表示X轴动作、T轴动作和Z轴动作的依赖属性,它可以被实际的业务数据源绑定。
当实际的业务数据发生改变时,轴动作属性相应改变,并VisualStateManager来转换控件的状态,以触发样式模板中的动画。
public class WaferRobotControl : Control
{
static WaferRobotControl()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(WaferRobotControl), new FrameworkPropertyMetadata(typeof(WaferRobotControl)));
} public static readonly DependencyProperty WaferProperty = DependencyProperty.Register("Wafer", typeof(int), typeof(WaferRobotControl));
public int Wafer { get => (int)GetValue(WaferProperty); set => SetValue(WaferProperty, value); } public static readonly DependencyProperty RobotZActionProperty = DependencyProperty.Register(
"RobotZAction",
typeof(WaferRobotZAction),
typeof(WaferRobotControl),
new PropertyMetadata(WaferRobotZAction.Z_Origin, RobotZActionPropertyChangedCallback)); public WaferRobotZAction RobotZAction
{
get => (WaferRobotZAction)GetValue(RobotZActionProperty);
set => SetValue(RobotZActionProperty, value);
} private static void RobotZActionPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as WaferRobotControl;
var oldAct = (WaferRobotZAction)e.OldValue;
var newAct = (WaferRobotZAction)e.NewValue;
switch (newAct)
{
case WaferRobotZAction.Z_Origin:
VisualStateManager.GoToState(control, newAct.ToString(), true);
break;
case WaferRobotZAction.Z_CW:
if (newAct != oldAct)
{
VisualStateManager.GoToState(control, newAct.ToString(), true);
}
break;
case WaferRobotZAction.Z_CCW:
if (newAct != oldAct)
{
VisualStateManager.GoToState(control, newAct.ToString(), true);
}
break;
default:
break;
}
} public static readonly DependencyProperty RobotXActionProperty = DependencyProperty.Register(
"RobotXAction",
typeof(WaferRobotXAction),
typeof(WaferRobotControl),
new PropertyMetadata(WaferRobotXAction.X_Origin, RobotXActionPropertyChangedCallback));
public WaferRobotXAction RobotXAction
{
get => (WaferRobotXAction)GetValue(RobotXActionProperty);
set => SetValue(RobotXActionProperty, value);
} private static void RobotXActionPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as WaferRobotControl;
var oldAct = (WaferRobotXAction)e.OldValue;
var newAct = (WaferRobotXAction)e.NewValue;
switch (newAct)
{
case WaferRobotXAction.X_Origin:
VisualStateManager.GoToState(control, newAct.ToString(), true);
break;
case WaferRobotXAction.X_CW:
if (newAct != oldAct)
{
VisualStateManager.GoToState(control, newAct.ToString(), true);
}
break;
case WaferRobotXAction.X_CCW:
if (newAct != oldAct)
{
VisualStateManager.GoToState(control, newAct.ToString(), true);
}
break;
default:
break;
}
} public static readonly DependencyProperty RobotTActionProperty = DependencyProperty.Register(
"RobotTAction",
typeof(WaferRobotTAction),
typeof(WaferRobotControl),
new PropertyMetadata(WaferRobotTAction.T_Origin, RobotTActionPropertyChangedCallback)); public WaferRobotTAction RobotTAction
{
get => (WaferRobotTAction)GetValue(RobotTActionProperty);
set => SetValue(RobotTActionProperty, value);
} private static void RobotTActionPropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var control = d as WaferRobotControl;
var oldAct = (WaferRobotTAction)e.OldValue;
var newAct = (WaferRobotTAction)e.NewValue;
switch (newAct)
{
case WaferRobotTAction.T_Origin:
VisualStateManager.GoToState(control, newAct.ToString(), true);
break;
case WaferRobotTAction.T_CW:
if (newAct != oldAct)
{
VisualStateManager.GoToState(control, newAct.ToString(), true);
}
break;
case WaferRobotTAction.T_CCW:
if (newAct != oldAct)
{
VisualStateManager.GoToState(control, newAct.ToString(), true);
}
break;
default:
break;
}
} public override void OnApplyTemplate()
{
base.OnApplyTemplate();
VisualStateManager.GoToState(this, WaferRobotZAction.Z_Origin.ToString(), true);
VisualStateManager.GoToState(this, WaferRobotXAction.X_Origin.ToString(), true);
VisualStateManager.GoToState(this, WaferRobotTAction.T_Origin.ToString(), true);
}
}
三 Style
控件模板的实现思路。
将机器人的样式分为三部分,不动的底座部分,Z轴部分,包含T轴和X轴的手臂部分。
VisualStateGroup中定义出轴动作的VisualState,编写转换动画。
<SolidColorBrush x:Key="robotBorderBrush" Color="#030303" />
<Style TargetType="{x:Type local:WaferRobotControl}" >
<Setter Property="Cursor" Value="Hand" />
<Setter Property="Width" Value="200"/>
<Setter Property="Height" Value="300"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:WaferRobotControl}">
<Viewbox x:Name="viewbox" Stretch="Fill">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="RobotActions">
<VisualStateGroup.Transitions>
<VisualTransition To="Z_CW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotZAct" Storyboard.TargetProperty="Y">
<LinearDoubleKeyFrame Value="-90" KeyTime="0:0:1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotUpDownAct" Storyboard.TargetProperty="Y">
<LinearDoubleKeyFrame Value="-90" KeyTime="0:0:1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition To="Z_CCW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotZAct" Storyboard.TargetProperty="Y">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:1"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotUpDownAct" Storyboard.TargetProperty="Y">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions>
<VisualState Name="Z_Origin">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotZAct" Storyboard.TargetProperty="Y" >
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotUpDownAct" Storyboard.TargetProperty="Y" >
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState Name="Z_CW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotZAct" Storyboard.TargetProperty="Y" Duration="0" >
<LinearDoubleKeyFrame Value="-90" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotUpDownAct" Storyboard.TargetProperty="Y" >
<LinearDoubleKeyFrame Value="-90" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState Name="Z_CCW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotZAct" Storyboard.TargetProperty="Y" >
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotUpDownAct" Storyboard.TargetProperty="Y" >
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup> <VisualStateGroup Name="RobotXActions">
<VisualStateGroup.Transitions>
<VisualTransition To="X_CW">
<Storyboard FillBehavior="HoldEnd" SpeedRatio="6">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT1RotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="90" KeyTime="0:0:0"/>
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:9"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2ArmRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="-90" KeyTime="0:0:0"/>
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:9"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2Act" Storyboard.TargetProperty="X">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:9"/>
<LinearDoubleKeyFrame Value="2.126" KeyTime="0:0:8"/>
<LinearDoubleKeyFrame Value="8.443" KeyTime="0:0:7"/>
<LinearDoubleKeyFrame Value="18.756" KeyTime="0:0:6"/>
<LinearDoubleKeyFrame Value="32.753" KeyTime="0:0:5"/>
<LinearDoubleKeyFrame Value="50.009" KeyTime="0:0:4"/>
<LinearDoubleKeyFrame Value="70" KeyTime="0:0:3"/>
<LinearDoubleKeyFrame Value="92.117" KeyTime="0:0:2"/>
<LinearDoubleKeyFrame Value="115.689" KeyTime="0:0:1"/>
<LinearDoubleKeyFrame Value="140" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition To="X_CCW">
<Storyboard FillBehavior="HoldEnd" SpeedRatio="6">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT1RotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
<LinearDoubleKeyFrame Value="90" KeyTime="0:0:9"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2ArmRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
<LinearDoubleKeyFrame Value="-90" KeyTime="0:0:9"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2Act" Storyboard.TargetProperty="X">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
<LinearDoubleKeyFrame Value="2.126" KeyTime="0:0:1"/>
<LinearDoubleKeyFrame Value="8.443" KeyTime="0:0:2"/>
<LinearDoubleKeyFrame Value="18.756" KeyTime="0:0:3"/>
<LinearDoubleKeyFrame Value="32.753" KeyTime="0:0:4"/>
<LinearDoubleKeyFrame Value="50.009" KeyTime="0:0:5"/>
<LinearDoubleKeyFrame Value="70" KeyTime="0:0:6"/>
<LinearDoubleKeyFrame Value="92.117" KeyTime="0:0:7"/>
<LinearDoubleKeyFrame Value="115.689" KeyTime="0:0:8"/>
<LinearDoubleKeyFrame Value="140" KeyTime="0:0:9"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions> <VisualState Name="X_Origin">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT1RotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="90" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2ArmRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="-90" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2Act" Storyboard.TargetProperty="X">
<LinearDoubleKeyFrame Value="140" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState> <VisualState Name="X_CW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT1RotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2ArmRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2Act" Storyboard.TargetProperty="X">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState Name="X_CCW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT1RotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="90" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2ArmRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="-90" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="armXT2Act" Storyboard.TargetProperty="X">
<LinearDoubleKeyFrame Value="140" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup> <VisualStateGroup Name="RobotTActions">
<VisualStateGroup.Transitions>
<VisualTransition To="T_Origin">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="90" KeyTime="0:0:1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition To="T_CW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="180" KeyTime="0:0:1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
<VisualTransition To="T_CCW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:1"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualTransition>
</VisualStateGroup.Transitions> <VisualState Name="T_Origin">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="90" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState Name="T_CCW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState Name="T_CW">
<Storyboard FillBehavior="HoldEnd">
<DoubleAnimationUsingKeyFrames Storyboard.TargetName="robotRotateAct" Storyboard.TargetProperty="Angle">
<LinearDoubleKeyFrame Value="180" KeyTime="0:0:0"/>
</DoubleAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Canvas Width="200" Height="300" >
<Canvas x:Name="robotZ" Width="40" Height="120" Canvas.Top="170" Canvas.Left="80" >
<Canvas.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="robotZAct"></TranslateTransform>
</TransformGroup>
</Canvas.RenderTransform>
<Path Stroke="#030303" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Fill>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
<GradientStop Color="#6B696A" Offset="0" />
<GradientStop Color="#6B696A" Offset="1" />
<GradientStop Color="#A1A7BE" Offset="0.5" />
</LinearGradientBrush>
</Path.Fill>
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0 20" IsClosed="True">
<LineSegment Point="0 2"/>
<LineSegment Point="2 2"/>
<LineSegment Point="5 5"/>
<LineSegment Point="35 5" />
<LineSegment Point="38 2"/>
<LineSegment Point="40 2"/>
<LineSegment Point="40 20" />
<LineSegment Point="0 20" />
</PathFigure> <PathFigure StartPoint="4 20" >
<LineSegment Point="4 24"/>
<LineSegment Point="36 24" />
<LineSegment Point="36 20"/>
</PathFigure> <PathFigure StartPoint="4 24" >
<LineSegment Point="2 24"/>
<LineSegment Point="2 28"/>
<LineSegment Point="4 28"/>
<LineSegment Point="36 28" />
<LineSegment Point="38 28" />
<LineSegment Point="38 24"/>
<LineSegment Point="36 24"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="#030303" StrokeStartLineCap="Round" StrokeEndLineCap="Round">
<Path.Fill>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
<GradientStop Color="#6B696A" Offset="0" />
<GradientStop Color="#6B696A" Offset="1" />
<GradientStop Color="#A1A7BE" Offset="0.5" />
</LinearGradientBrush>
</Path.Fill>
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="2 28.5" >
<LineSegment Point="2 120"/>
<LineSegment Point="38 120"/>
<LineSegment Point="38 28.5"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Canvas> <Canvas x:Name="dizuo" Width="80" Height="100" Canvas.Top="200" Canvas.Left="60">
<Path Stroke="#030303" Fill="#A1A7BE" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0 0" IsClosed="True">
<LineSegment Point="20 0"/>
<LineSegment Point="20 92"/>
<LineSegment Point="0 92"/>
</PathFigure>
<PathFigure StartPoint="0 92" IsClosed="True">
<LineSegment Point="12 92"/>
<LineSegment Point="12 100"/>
<LineSegment Point="0 100"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="#030303" Fill="#7A7E90" Canvas.Left="20">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0 0" IsClosed="True">
<LineSegment Point="40 0"/>
<LineSegment Point="40 92"/>
<LineSegment Point="0 92"/>
</PathFigure>
<PathFigure StartPoint="0 92" IsClosed="True">
<LineSegment Point="-8 92"/>
<LineSegment Point="-8 100"/>
<LineSegment Point="48 100"/>
<LineSegment Point="48 92"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="#030303" Fill="#585368" Canvas.Left="60">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0 0" IsClosed="True">
<LineSegment Point="20 0"/>
<LineSegment Point="20 92"/>
<LineSegment Point="0 92"/>
</PathFigure>
<PathFigure StartPoint="8 92" IsClosed="True">
<LineSegment Point="20 92"/>
<LineSegment Point="20 100"/>
<LineSegment Point="8 100"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Canvas> <Canvas x:Name="robot" Width="100" Height="150" RenderTransformOrigin="1 1" >
<Canvas.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="robotRotateAct"/>
<TranslateTransform x:Name="robotUpDownAct"></TranslateTransform>
</TransformGroup>
</Canvas.RenderTransform>
<Canvas x:Name="armXT1" Width="200" Height="100" Canvas.Top="100" RenderTransformOrigin="0.5 0.5">
<Canvas.RenderTransform>
<RotateTransform x:Name="armXT1RotateAct"/>
</Canvas.RenderTransform> <Canvas x:Name="armXT1Arm" Width="70" Height="30" Canvas.Left="30" Canvas.Top="35" RenderTransformOrigin="1 0.5">
<Path Stroke="{StaticResource robotBorderBrush}" Fill="#FF7F50" StrokeThickness="1" StrokeEndLineCap="Round" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0 5" IsClosed="True">
<LineSegment Point="51 0"/>
<LineSegment Point="51 30" IsStroked="False"/>
<LineSegment Point="0 25"/>
<LineSegment Point="0 5" IsStroked="False"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="{StaticResource robotBorderBrush}" StrokeThickness="1" Canvas.Left="0"
StrokeEndLineCap="Round" StrokeStartLineCap="Round" Fill="#FF7F50"
Data="M 0,5 A 10,10 0 0 0 0,25">
</Path>
</Canvas> <Canvas x:Name="armXT1Center" Width="40" Height="40" Canvas.Left="80" Canvas.Top="30" >
<Path Stroke="{StaticResource robotBorderBrush}" Fill="#FF7F50" StrokeThickness="1" StrokeEndLineCap="Round" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="0 6" IsClosed="True">
<LineSegment Point="6 0"/>
<LineSegment Point="34 0"/>
<LineSegment Point="40 6"/>
<LineSegment Point="40 34"/>
<LineSegment Point="34 40"/>
<LineSegment Point="6 40"/>
<LineSegment Point="0 34"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
</Canvas>
</Canvas> <Canvas x:Name="armXT2" Width="120" Height="40" Canvas.Left="-90" Canvas.Top="130">
<Canvas.RenderTransform>
<TransformGroup>
<TranslateTransform x:Name="armXT2Act"></TranslateTransform>
</TransformGroup>
</Canvas.RenderTransform>
<Canvas x:Name="armXT2Arm" Width="70" Height="20" Canvas.Left="50" Canvas.Top="10" RenderTransformOrigin="0 0.5" Background="#6495ED">
<Canvas.RenderTransform>
<RotateTransform x:Name="armXT2ArmRotateAct"/>
</Canvas.RenderTransform>
<Path Stroke="{StaticResource robotBorderBrush}" StrokeThickness="1" Canvas.Left="70"
StrokeEndLineCap="Round" StrokeStartLineCap="Round" Fill="#6495ED"
Data="M 0,0 A 10,10 0 0 1 0,20">
</Path>
<Path Stroke="{StaticResource robotBorderBrush}" StrokeThickness="1" Canvas.Left="0"
StrokeEndLineCap="Round" StrokeStartLineCap="Round" Fill="#6495ED"
Data="M 0,0 A 10,10 0 0 0 0,20">
</Path> <Path Stroke="{StaticResource robotBorderBrush}" Fill="#6495ED" StrokeThickness="1" StrokeEndLineCap="Round" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="70 0" >
<LineSegment Point="0 0" />
<LineSegment Point="0 20" IsStroked="False"/>
<LineSegment Point="70 20"/>
<LineSegment Point="70 0" IsStroked="False"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Ellipse Width="12" Height="12" Stroke="#030303" StrokeThickness="2" Fill="Transparent"
Canvas.Top="4" Canvas.Left="62"/>
</Canvas> <Canvas x:Name="armGripper" Height="40" Width="50" Canvas.Left="0" Canvas.Top="0">
<Path Stroke="{StaticResource robotBorderBrush}" StrokeThickness="2" StrokeEndLineCap="Round" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="30 14" >
<LineSegment Point="10 14" />
<LineSegment Point="4 8" />
<LineSegment Point="-6 8" />
</PathFigure> <PathFigure StartPoint="30 26" >
<LineSegment Point="10 26" />
<LineSegment Point="4 32" />
<LineSegment Point="-6 32" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="{StaticResource robotBorderBrush}" Fill="#7A7E90" StrokeThickness="1" StrokeEndLineCap="Round" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="40 0" >
<LineSegment Point="60 0" />
<LineSegment Point="60 40" />
<LineSegment Point="40 40" />
<LineSegment Point="30 30" />
<LineSegment Point="30 10" />
<LineSegment Point="40 0" />
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
<Path Stroke="{StaticResource robotBorderBrush}" Fill="#7A7E90" StrokeThickness="1" StrokeEndLineCap="Round" >
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="30 10" >
<LineSegment Point="20 10" />
<LineSegment Point="20 30" />
<LineSegment Point="30 30" />
<LineSegment Point="30 10" IsStroked="False"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path> <Ellipse Width="12" Height="12" Stroke="#030303" StrokeThickness="2" Fill="Transparent"
Canvas.Top="14" Canvas.Left="44"/>
<Ellipse x:Name="wafer" Width="40" Height="40" StrokeThickness="1" Stroke="Black" Canvas.Left="-24"
Visibility="{Binding Wafer,Converter={StaticResource WaferIntToVisibilityConverter},
RelativeSource={RelativeSource TemplatedParent}}"
Fill="{Binding Wafer,Converter={StaticResource WaferIntToColorConverter},
RelativeSource={RelativeSource TemplatedParent}}"/>
</Canvas>
</Canvas>
</Canvas>
</Canvas>
</Viewbox>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
四 效果演示
界面代码如下:
<Window x:Class="WpfApp1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:wpfapp1="clr-namespace:WpfApp1"
mc:Ignorable="d" Background="WhiteSmoke"
Title="MainWindow" Height="800" Width="1200">
<Canvas>
<wpfapp1:WaferRobotControl Canvas.Left="472" Canvas.Top="171" x:Name="robot"/>
<Button Content="Z CW" Canvas.Left="757" Canvas.Top="338" Width="60" Height="30" Click="ZCWButton_Click" />
<Button Content="Z CCW" Canvas.Left="757" Canvas.Top="388" Width="60" Height="30" Click="ZCCWButton_Click"/>
<Button Content="X CW" Canvas.Left="838" Canvas.Top="338" Width="60" Height="30" Click="XCWButton_Click"/>
<Button Content="X CCW" Canvas.Left="838" Canvas.Top="389" Width="60" Height="30" Click="XCCWButton_Click"/>
<Button Content="T CW" Canvas.Left="919" Canvas.Top="338" Width="60" Height="30" Click="TCWButton_Click"/>
<Button Content="T CCW" Canvas.Left="919" Canvas.Top="389" Width="60" Height="30" Click="TCCWButton_Click"/>
<Button Content="Auto" Canvas.Left="757" Canvas.Top="439" Width="60" Height="30" Click="AutoButton_Click"/>
</Canvas>
</Window>
后台代码如下:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
} private void ZCWButton_Click(object sender, RoutedEventArgs e)
{
robot.RobotZAction = WaferRobotZAction.Z_CW;
} private void ZCCWButton_Click(object sender, RoutedEventArgs e)
{
robot.RobotZAction = WaferRobotZAction.Z_CCW;
} private void XCWButton_Click(object sender, RoutedEventArgs e)
{
robot.RobotXAction = WaferRobotXAction.X_CW;
} private void XCCWButton_Click(object sender, RoutedEventArgs e)
{
robot.RobotXAction = WaferRobotXAction.X_CCW;
} private void TCWButton_Click(object sender, RoutedEventArgs e)
{
robot.RobotTAction = WaferRobotTAction.T_CW;
} private void TCCWButton_Click(object sender, RoutedEventArgs e)
{
robot.RobotTAction = WaferRobotTAction.T_CCW;
} private void AutoButton_Click(object sender, RoutedEventArgs e)
{
Task.Run(async () =>
{
Application.Current.Dispatcher?.Invoke
(
() => { this.robot.RobotTAction = WaferRobotTAction.T_CCW; }
);
await Task.Delay(1000); Application.Current.Dispatcher?.Invoke
(
() => { this.robot.RobotXAction = WaferRobotXAction.X_CW; }
);
await Task.Delay(2000); Application.Current.Dispatcher?.Invoke(
() => { this.robot.Wafer = 1; }
);
await Task.Delay(200); Application.Current.Dispatcher?.Invoke(
() => { this.robot.RobotXAction = WaferRobotXAction.X_CCW; }
);
await Task.Delay(2000); Application.Current.Dispatcher?.Invoke(
() => { this.robot.RobotZAction = WaferRobotZAction.Z_CW; }
);
await Task.Delay(1000); Application.Current.Dispatcher?.Invoke
(
() => { this.robot.RobotTAction = WaferRobotTAction.T_CW; }
);
await Task.Delay(1000); Application.Current.Dispatcher?.Invoke
(
() => { this.robot.RobotXAction = WaferRobotXAction.X_CW; }
);
await Task.Delay(2000); Application.Current.Dispatcher?.Invoke(
() => { this.robot.Wafer = 0; }
);
await Task.Delay(200); Application.Current.Dispatcher?.Invoke(
() => { this.robot.RobotXAction = WaferRobotXAction.X_CCW; }
);
await Task.Delay(2000);
Application.Current.Dispatcher?.Invoke
(
() => { this.robot.RobotTAction = WaferRobotTAction.T_Origin; }
);
await Task.Delay(1000);
Application.Current.Dispatcher?.Invoke
(
() => { this.robot.RobotZAction = WaferRobotZAction.Z_CCW; }
);
await Task.Delay(1000);
});
}
}
WPF开发经验-实现一种三轴机械手控件的更多相关文章
- Jquery如何序列化form表单数据为JSON对象 C# ADO.NET中设置Like模糊查询的参数 从客户端出现小于等于公式符号引发检测到有潜在危险的Request.Form 值 jquery调用iframe里面的方法 Js根据Ip地址自动判断是哪个城市 【我们一起写框架】MVVM的WPF框架(三)—数据控件 设计模式之简单工厂模式(C#语言描述)
jquery提供的serialize方法能够实现. $("#searchForm").serialize();但是,观察输出的信息,发现serialize()方法做的是将表单中的数 ...
- WPF自定义控件(三)の扩展控件
扩展控件,顾名思义就是对已有的控件进行扩展,一般继承于已有的原生控件,不排除继承于自定义的控件,不过这样做意义不大,因为既然都自定义了,为什么不一步到位呢,有些不同的需求也可以通过此来完成,不过类似于 ...
- WPF编程,通过Double Animation动态旋转控件的一种方法。
原文:WPF编程,通过Double Animation动态旋转控件的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/art ...
- WPF编程,通过Double Animation动态更改控件属性的一种方法。
原文:WPF编程,通过Double Animation动态更改控件属性的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/a ...
- WPF编程,通过Double Animation动态缩放控件的一种方法。
原文:WPF编程,通过Double Animation动态缩放控件的一种方法. 版权声明:我不生产代码,我只是代码的搬运工. https://blog.csdn.net/qq_43307934/art ...
- WPF 自定义ComboBox样式,自定义多选控件
原文:WPF 自定义ComboBox样式,自定义多选控件 一.ComboBox基本样式 ComboBox有两种状态,可编辑和不可编辑状态.通过设置IsEditable属性可以切换控件状态. 先看基本样 ...
- Windows Presentation Foundation(WPF)中的数据绑定(使用XmlDataProvider作控件绑定)
原文:Windows Presentation Foundation(WPF)中的数据绑定(使用XmlDataProvider作控件绑定) ------------------------------ ...
- WPF教程十一:简单了解并使用控件模板
WPF教程十一:简单了解并使用控件模板 这一章梳理控件模板,每个WPF控件都设计成无外观的,但是行为设计上是不允许改变的,比如使用Button的控件时,按钮提供了能被点击的内容,那么自由的改变控件外观 ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇
原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 前篇 第三章 为控件添加事件 好了,我们之前以前开发一个控件.而且也添加了属性,开发也很规范,但是那个控件还差最后一点:添加事件. 系列 ...
- ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇
原文:ASP.NET自定义控件组件开发 第三章 为控件添加事件 后篇 第三章 为控件添加事件 后篇 前一篇文章只是简单的说了下事件,但是大家应该方法,在ASP.NET自定义控件中只是简单那么定义事件是 ...
随机推荐
- Python--网络编程学习笔记系列01 附实战:udp聊天器
Python--网络编程学习系列笔记01 网络编程基本目标: 不同的电脑上的软件能够实现数据传输 网络编程基础知识: IP地址: 用来在网络中标记一台电脑 网络号+主机号(按网络号和主机号占位分类A ...
- docker容器化业务
1.环境准备: 设备 IP地址 作用 系统版本 mysql-master 192.168.100.213 Nginx-Web服务器 Ubuntu2004 mysql-slave 192.168.100 ...
- [Android开发学iOS系列] Auto Layout
[Android开发学iOS系列] Auto Layout 内容: 介绍什么是Auto Layout. 基本使用方法 在代码中写约束的方法 Auto Layout的原理 尺寸和优先级 Auto Lay ...
- Spark简单介绍,Windows下安装Scala+Hadoop+Spark运行环境,集成到IDEA中
一.前言 近几年大数据是异常的火爆,今天小编以java开发的身份来会会大数据,提高一下自己的层面! 大数据技术也是有很多: Hadoop Spark Flink 小编也只知道这些了,由于Hadoop, ...
- 有依赖的背包问题(Acwing 10)
1 # include<iostream> 2 # include<cstring> 3 # include<algorithm> 4 using namespac ...
- 微信DAT文件解密(dat转图像)
微信电脑版现在已经是日常工作生活必不可少的工具,有时候删除了聊天记录或者被系统清理软件清理了,但还想查看曾经的微信聊天图片. 这个时候辛辛苦苦找到了文件,却发现无法查看,因为微信电脑版为了保护我们的隐 ...
- golang实现一个简单的http代理
代理是网络中的一项重要的功能,其功能就是代理网络用户去取得网络信息.形象的说:它是网络信息的中转站,对于客户端来说,代理扮演的是服务器的角色,接收请求报文,返回响应报文:对于web服务器来说,代理扮演 ...
- 更换K8S证书可用期
帮助文档:https://zealous-cricket-cfa.notion.site/kubeadm-k8s-24611be9607c4b3193012de58860535e 解决: 1.安装GO ...
- 2022春每日一题:Day 11
题目:高斯消元法 高斯消元法是一个模板,下面简单介绍其内容以及实现方法. 高斯消元是求一个求多元一次方程组的解的算法. 就是形式如下的关于x1,x2...xn的方程组的解. a11x1 + a12x2 ...
- Kubernetes_从零开始搭建k8s集群(亲测可用)
一.前言 本文讲述从零开始搭建k8s集群,均使用国内镜像,版本均统一,使用两个虚拟机,一个主节点,一个从节点,保证k8s一次搭建成功. 注意:Kubernetes,简称K8s,是用8代替名字中间的8个 ...