在 WPF 中绘制一个网格覆盖的圆柱体
一个简单的程序,用于在 2D 中绘制一系列几何图形,这些图形代表一个网格覆盖的 3 维圆柱体。

引言
这是一个简单、初学者级别的项目,它从用户那里获取一些尺寸,然后使用仅 2D 几何图形绘制 3 维圆柱体的表示。这里涵盖了基本概念,例如简单的数据绑定和属性更改通知,以及简单的 Geometry 和 Path 对象。
源代码中包含的项目除了各种大小圆柱体的图形显示之外,没有其他用途。本文的目的是提供一个基本的 WPF 窗口的起点,以及在 Canvas
对象上进行基本图形绘制的起点。从这个简单的基础出发,可以添加大量的特性和选项,使这个项目更有用。
背景
这个项目/文章对我来说有两个目的
- 我终于要学习 C# 了。我多年来一直是 VB 程序员,所以这是一个快速而简单的入门项目。
- 我需要复习一下我在 WPF 中的 2D 绘图技能。
我也对 StackOverflow 上提出的一个问题很感兴趣,这个问题提出了这种类型的问题。它看起来很有趣,足以想出一个完整的解决方案。
Using the Code
WPF 中的窗口布局非常基本
<Grid>
<Grid.Background>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="#FFBABABA" Offset="1" />
<GradientStop Color="#FFE5E5E5" Offset="0" />
</LinearGradientBrush>
</Grid.Background>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" Margin="10,0">
<TextBlock Margin="10" Text="Draw a cylinder with gridlines"
TextWrapping="Wrap" MaxWidth="150"
TextAlignment="Center"/>
<TextBlock Text="Height:"/>
<TextBox Text="{Binding Path=CylinderHeight}"/>
<TextBlock Text="Radius:"/>
<TextBox Text="{Binding Path=CylinderRadius}"/>
<TextBlock Text="Divisions:"/>
<TextBox Text="{Binding Path=CylinderDivisions}"/>
<Button Margin="5,10" Click="ClickButton">
Draw Cylinder
</Button>
</StackPanel>
<Canvas Name="Canvas1" Grid.Column="1">
<Canvas.Background>
<LinearGradientBrush EndPoint="0,0" StartPoint="1,1">
<GradientStop Color="#FFE2C98B" Offset="0" />
<GradientStop Color="#FFFCEED2" Offset="1" />
</LinearGradientBrush>
</Canvas.Background>
</Canvas>
</Grid>
您会注意到在上面的 XAML 中,唯一带有名称的控件是 Canvas
,因为当单击“绘制圆柱体”按钮时,该控件会传递到另一个类。这演示了 WPF 的一个不错的特性。即使绑定到数据的文本框也不需要显式名称。
数据绑定非常基本,只是将 3 个文本框的 Text
属性绑定到 DrawingClass
类的相应属性。为了完成数据绑定,窗口的构造函数实例化了 DrawingClass
的一个新实例,并将其作为窗口的数据上下文(如下所示)
public DrawingClass dc;
public MainWindow()
{
InitializeComponent();
dc = new DrawingClass();
this.DataContext = dc;
}
下面是用于绘制圆柱体形状和代表圆柱体底部的弧线的代码片段。Canvas
对象传递给这个子例程,以便可以将各种几何图形直接添加到它上面。
public void DrawCylinder(System.Windows.Controls.Canvas cnv)
{
//Clear the existing children from the canvas.
cnv.Children.Clear();
圆柱体顶部宽度与其高度的比例任意设置为 0.3,以便给人一种从圆柱体上方略微观看圆柱体的 3D 印象。
然后计算描述圆柱体对象的 4 个点,以及一个 ptC
点,它是构成圆柱体顶部表面的椭圆的中心。
int ellipseHeight = Convert.ToInt32( Math.Floor(cylinderRadius * 0.3));
Point ptUpperLeft = new Point(30, ellipseHeight*2);
Point ptUpperRight = new Point(30 + (cylinderRadius * 2), ptUpperLeft.Y);
Point ptLowerLeft = new Point(30, ptUpperLeft.Y + cylinderHeight);
Point ptLowerRight = new Point(ptUpperLeft.X +
(cylinderRadius * 2), ptUpperLeft.Y + cylinderHeight);
Point ptC = new Point(30 + cylinderRadius,ptUpperLeft.Y);
创建一个新的 Path
对象,该对象将包含各种 Geometry
和 PathFigure
Segments
。然后将此路径添加到 Canvas
。代码的其余部分未在此处显示,但使用类似的技术将其余图形添加到 Canvas
。
Path pth = new Path();
//Draw cylinder body.
LineSegment ln = new LineSegment(ptLowerLeft,true);
ArcSegment arc = new ArcSegment(ptLowerRight,new Size(cylinderRadius,ellipseHeight),
0,false,System.Windows.Media.SweepDirection.Counterclockwise,true);
PathFigure pf = new PathFigure();
pf.StartPoint = ptUpperLeft;
//Add left side of cylinder.
pf.Segments.Add(ln);
//Add bottom arc of cylinder.
pf.Segments.Add(arc);
ln = new LineSegment(ptUpperRight,true);
//Add right side of cylinder.
pf.Segments.Add(ln);
PathGeometry pg = new PathGeometry();
pg.Figures.Add(pf);
pth.Stroke = new SolidColorBrush(Colors.Black);
pth.StrokeThickness = 2;
pth.Fill = new SolidColorBrush(Colors.White);
pth.Data = pg;
//Add path to the canvas.
cnv.Children.Add(pth);
关注点
在绘制弧线时,最简单的对象是 ArcSegment
对象。简单的线条可以同样容易地用 LineGeometry
或 LineSegment
对象表示。最容易绘制完整的椭圆的是使用 EllipseGeometry
对象。
历史
- 2012 年 1 月 27 日:初始发布