WPF开发之实现一种三轴机械手控件
作者:一团静火 发布时间:2021-10-29 19:16:29
标签: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);
});
}
}
来源:https://www.cnblogs.com/wwwen/p/17076289.html


猜你喜欢
- 使用volley进行网络请求:需先将volley包导入androidstudio中File下的Project Structrue,点加号导包
- 排序二叉树概念二叉排序树(Binary Sort Tree),又称二叉查找树(Binary Search Tree),亦称二叉搜索树。是数据
- 本文将介绍一段实例代码,来讲解利用正则表达式使C#判断输入日期格式是否正确的方法。希望这段代码能对大家有所帮助。 通常我们在用C#
- 前言最近写一个东东,可能会考虑到字符串拼接,想了几种方法,但对性能未知,所以下面就来测试下面,话不多说了,来一起看看详细的介绍吧。示例代码p
- 原始数据:string input = "3,7,2,8,1,9,1,34,67,78,22";要处理为:string[
- 最近工作需要,自定了一个颜色选择器,效果图如下:颜色种类是固定的,圆环上有个指示器,指示选中的颜色,这个定义起来应该是很简单了,直接上代码。
- 1.设计思路,使用VersionCode定义为版本升级参数。android为我们定义版本提供了2个属性:<manifest packa
- 1、 题外话 相信大家对LayoutInflate都不陌生,特别在ListView的Adapter的getV
- Android CardView详解Android5.0中向我们介绍了一个全新的控件–CardView,从本质上看,可以将Car
- 获取接口调用凭据①接口说明access_token是公众号的全局唯一票据,公众号调用各接口时都需使用access_token。开发者需要进行
- 一.相关知识:Java多线程程序设计到的知识:(一)对同一个数量进行操作(二)对同一个对象进行操作(三)回调方法使用(四)线程同步,死锁问题
- 数据访问之Druid数据源的使用说明:该数据源Druid,使用自定义方式实现,后面文章使用start启动器实现,学习思路为主。为什么要使用数
- 第一步,导入jar包<!--Redis--> <dependency
- Data Annotations是在Asp.Net中用于表单验证的,它通过Attribute直接标记字段的有效性,简单且直观。在非Asp.N
- Jmeter是纯Java开发的, 能够运行Java程序的系统一般都可以运行Jmeter, 如:Windows、 Linux、 mac等。由于
- import java.util.Scanner;public class VariableExchange { &n
- 日常使用中spring的 @Cacheable 大家一定不陌生,基于aop机制的缓存实现,并且可以选择cacheManager具体提供缓存的
- 一对一查询一对一查询的模型用户表和订单表的关系为,一个用户有多个订单,一个订单只从属于一个用户。一对一查询的需求:查询一个订单,与此同时查询
- 员工管理系统要求如下:通过面向对象的编程思想,实现员工信息的增删改查,存储结构为数组。限定数组长度为100。实现页面:添加员工查找员工修改员
- 我们经常会看到有一些app的banner界面可以实现循环播放多个广告图片和手动滑动循环的效果。看到那样的效果,相信大家都会想到ViewPag