Canvas、StackPanel、Grid三者之间的关系

本文介绍了Silverlight中的三种常用布局控件:Canvas、StackPanel和Grid。详细解释了每种控件的特点及应用场景,包括绝对定位、横向或纵向排列以及通过行列表格管理布局的方法。

Silverlight提供了非常灵活的布局管理系统,让程序员和美工可以非常方便的控制控件的位置。布局管理系统提供了两种布局方式:绝对定位和相对定位。这两种定位方式其实和HTML的两种定位方式是一样的。在Silverlight 2 beta1中内置了三种最常用的布局控件:Canvas、StackPanel、Grid。 
一、Canvas:相当基础的控件,通过绝对定位来控制字控件的位置。 
在Canvas中,我们使用一种叫做“附加属性”的XMAL新特性来控制子控件的位置。附加属性就是指你可以通过设置子控件相对于其父控件的Top、Left、Bottom和Right值来控制子控件的位置。在Canvas中,我们可以使用Canvas.Left、Canvas.Top来控制子控件相对于父控件(Canvas)的位置。如: 
 
以上代码将显示为: 
 
Canvas对于那些子控件不需要移动的布局是非常方便的,但如果子控件数量太多或是子控件位置会发生变化,使用Canvas就不大方便了。这时候可以使用其他的布局控件,如:StackPanel、Grid。 
二、StackPanel:该控件用于横向或纵向排列子控件(默认是纵向排列子控件的)。通过子控件的Margin属性(该属性和HTML的Margin属性的效果一样)来控制控件的间距。如: 
 
以上代码将显示为: 
 
三、Grid:Grid是一种相当灵活的布局控件,它通过行列的表格来管理子控件的布局,类似于HTML里的Table控件。 
和HTML的Table控件不同的是,你不能直接把子控件嵌套的单元格中。在Grid里,你得先使用<Grid.RowDefinitions>和<Grid.ColumnDefinitions>来定义Grid的行列结构;然后在子控件中使用Grid的附加属性来控制子控件所属的单元格。 
下面是一个使用Grid布局的例子,请注意控件所属的单元格: 
 
以上代码将显示为: 
 
对这三个基本布局控件有所了解后,我们就可以很方便的管理页面上控件的布局了。

很生动 看了后对三者之间的关系 有了很深入的理解

<Window x:Class="DoubleArmSimulation.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:local="clr-namespace:DoubleArmSimulation" xmlns:converters="clr-namespace:DoubleArmSimulation.Converters" mc:Ignorable="d" Title="双机械臂模拟系统" Height="750" Width="950"> <Window.Resources> </Window.Resources> <Grid> <Grid.ColumnDefinitions> <ColumnDefinition Width="Auto"/> <ColumnDefinition Width="*"/> </Grid.ColumnDefinitions> <StackPanel Grid.Column="0" Width="200" Background="AntiqueWhite" Margin="10"> <!-- 串口--> <!--<GroupBox Header="串口设置" Margin="5"> <StackPanel> <ComboBox x:Name="cmbPort" Margin="5" ItemsSource="{Binding AvailablePorts}" IsEnabled="False"/> <Button Content="打开串口" Margin="5" Background="White" /> <Button Content="关闭串口" Margin="5" Background="White" /> </StackPanel> </GroupBox>--> <!-- 机械臂长度设置 --> <GroupBox Header="机械臂长度" Margin="5"> <StackPanel> <StackPanel Orientation="Horizontal" Margin="5"> <TextBlock Text="L1长度 (cm):" VerticalAlignment="Center" Width="90"/> <TextBox Width="60" Text="{Binding Arm1Length, UpdateSourceTrigger=PropertyChanged}"/> </StackPanel> <StackPanel Orientation="Horizontal" Margin="5"> <TextBlock Text="L2长度 (cm):" VerticalAlignment="Center" Width="90"/> <TextBox Width="60" Text="{Binding Arm2Length, UpdateSourceTrigger=PropertyChanged}"/> </StackPanel> </StackPanel> </GroupBox> <!-- 坐标输入 --> <GroupBox Header="目标坐标输入" Margin="5"> <StackPanel> <StackPanel Orientation="Horizontal" Margin="5"> <TextBlock Text="X (cm):" VerticalAlignment="Center" Width="50"/> <TextBox x:Name="txtTargetX" Width="70" Text="{Binding TargetX, UpdateSourceTrigger=PropertyChanged}"/> </StackPanel> <StackPanel Orientation="Horizontal" Margin="5"> <TextBlock Text="Y (cm):" VerticalAlignment="Center" Width="50"/> <TextBox x:Name="txtTargetY" Width="70" Text="{Binding TargetY, UpdateSourceTrigger=PropertyChanged}"/> </StackPanel> <Button Content="设置目标点" Margin="10" Height="25" Background="LightGreen" Command="{Binding SetTargetCommand}"/> </StackPanel> </GroupBox> <!-- 随机生成坐标按钮 --> <Button Content="随机生成坐标" Margin="10" Height="20" Background="LightGoldenrodYellow" Command="{Binding GenerateTargetCommand}"/> <!-- 画圆功能 --> <!--<GroupBox Header="画圆" Margin="5"> <StackPanel> <StackPanel Orientation="Horizontal" Margin="5"> <TextBlock Text="直径 (cm):" VerticalAlignment="Center" Width="70"/> <TextBox x:Name="txtDiameter" Width="90" Text="{Binding CircleDiameter, UpdateSourceTrigger=PropertyChanged}"/> </StackPanel> <StackPanel Orientation="Horizontal" Margin="5"> <TextBlock Text="轨迹点数:" VerticalAlignment="Center" Width="70"/> <ComboBox x:Name="cmbPoints" SelectedValue="{Binding CirclePointCount}" SelectedValuePath="Tag"> <ComboBoxItem Content="16" Tag="16"/> <ComboBoxItem Content="32" Tag="32"/> <ComboBoxItem Content="64" Tag="64" IsSelected="True"/> <ComboBoxItem Content="128" Tag="128"/> </ComboBox> </StackPanel> <Button Content="开始" Margin="10" Height="30" Command="{Binding StartCircleCommand}"/> <Button Content="停止" Margin="10,0,10,10" Height="30" Background="LightBlue" Command="{Binding StopMotionCommand}"/> </StackPanel> </GroupBox>--> <!-- 位置信息显示 --> <GroupBox Header="当前位置信息" Margin="5,10,5,0"> <StackPanel> <TextBlock Text="{Binding CurrentPosition}" Margin="5"/> <TextBlock Text="{Binding JointAngles}" Margin="5"/> <TextBlock Text="{Binding SolutionType}" Margin="5"/> <TextBlock Text="{Binding MotionStatus}" Margin="5" Foreground="Blue" FontWeight="Bold"/> </StackPanel> </GroupBox> </StackPanel> <Grid Grid.Column="1" Margin="10"> <Canvas x:Name="canvas" Background="White"> </Canvas> </Grid> </Grid> </Window> 根据该MainWindow.xaml,请制作出项目 以下是实现思路 1.实现claer刷新每当随机目标点生成时使用 2.画(x,y)目标点 3.画出原点(0,0) 4.找到l1的末端 5.根据逆运算公式计算出(x1,y1的值) 6.将三点进行连线 using System; namespace DoubleArmSimulation.Models { public class RobotKinematicsModel { public double Length1 { get; } public double Length2 { get; } public InverseKinematicsSolution Solutions { get; private set; } public RobotKinematicsModel(double l1, double l2) { if (l1 <= 0 || l2 <= 0) throw new ArgumentOutOfRangeException("机械臂长度必须大于0"); Length1 = l1; Length2 = l2; } public bool CalculateIK(double x, double y) { const double tolerance = 1e-6; double d_sq = x * x + y * y; double maxReach = Length1 + Length2; double minReach = Math.Abs(Length1 - Length2); // 检查是否在原点 if (Math.Abs(x) < tolerance && Math.Abs(y) < tolerance) return false; // 检查是否在工作空间内 if (d_sq > maxReach * maxReach + tolerance || d_sq < minReach * minReach - tolerance) return false; // 计算θ₂余弦 double cosTheta2 = (d_sq - Length1 * Length1 - Length2 * Length2) / (2 * Length1 * Length2); cosTheta2 = Clamp(cosTheta2, -1.0, 1.0); double theta2 = Math.Acos(cosTheta2); double theta2_alt = -theta2; // 计算θ₁ double gamma = Math.Atan2(y, x); double beta = Math.Acos((Length1 * Length1 + d_sq - Length2 * Length2) / (2 * Length1 * Math.Sqrt(d_sq))); beta = Clamp(beta, 0, Math.PI); double theta1_up = gamma - beta; double theta1_down = gamma + beta; // 存储解决方案 Solutions = new InverseKinematicsSolution( NormalizeAngle(theta1_up), theta2, NormalizeAngle(theta1_down), theta2_alt ); return true; } public static double Clamp(double value, double min, double max) { return value < min ? min : value > max ? max : value; } private double NormalizeAngle(double angle) { angle %= 2 * Math.PI; if (angle > Math.PI) angle -= 2 * Math.PI; if (angle < -Math.PI) angle += 2 * Math.PI; return angle; } } }
最新发布
08-01
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值