视线 - 创建 WPF 自定义控件






4.93/5 (13投票s)
使用 WPF 和 C# 创建自定义控件。
EyeDemo 应用程序

引言
本文演示了如何使用 WPF 和 C# 创建一个基于自定义控件的眼睛。
这个想法源自我之前的文章:Eyes (构建完美的无用控件)。
背景
创建“眼睛”的文章让我思考,使用 WPF 和 3D 对象是否更容易实现相同的功能。我尝试了一些想法,结果很快就出来了,但 XAML 代码很混乱。使用自定义控件隐藏混乱似乎很自然。
类和架构

创建应用程序涉及 3 个类。Eye
和 Ball
类将属性映射到样式,而 Sphere
类为 Eye
样式创建一个资源。
使用 Eye
控件可以通过从工具箱拖动 Eye
控件或使用以下示例 XAML 代码来完成
<EyeControl:Eye RotationYAxis="180" RotationXAxis="0" PupilSize="1" IrisSize="0.7" />
请记住设置 namespace
(命名空间)
xmlnss:EyeControl="clr-namespace:EyeControl;assembly=EyeControl"
设计和样式
设计元素
创建 Eye
使用以下元素

这些元素的实现可以在 Eye
样式中找到(包含在 /Themes/Generic.xaml 中)。
“眼睛”样式
<!-- Eye -->
<Style TargetType="{x:Type local:Eye}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:Eye}">
<Border Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}">
<Viewport3D x:Name="viewPort"
Margin="4" Grid.Column="0">
<Viewport3D.Camera>
...
</Viewport3D.Camera>
<Viewport3D.Children>
<ModelVisual3D>
<ModelVisual3D.Content>
<Model3DGroup>
<GeometryModel3D Geometry="{Binding Source=
{StaticResource sphere}, Path=Geometry}">
<GeometryModel3D.Material>
<MaterialGroup>
<!-- (Egg)White -->
<DiffuseMaterial Brush="#FFFFFFFF" />
<!-- Iris -->
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<VisualBrush Stretch="None" Opacity="1">
<VisualBrush.Visual>
<Ellipse Width=".16"
Height=".29" StrokeThickness=".005"
Stroke="{Binding Path=IrisRimColor,
RelativeSource={RelativeSource TemplatedParent}}">
<Ellipse.Fill>
<RadialGradientBrush GradientOrigin=".5,.5">
<GradientStop Color="{Binding Path=IrisInnerColor,
RelativeSource={RelativeSource TemplatedParent}}"
Offset="0.0" />
<GradientStop Color=
"{Binding Path=IrisMiddleColor,
RelativeSource={RelativeSource TemplatedParent}}"
Offset="0.5" />
<GradientStop Color=
"{Binding Path=IrisOuterColor,
RelativeSource={RelativeSource TemplatedParent}}"
Offset="1.0" />
</RadialGradientBrush>
</Ellipse.Fill>
</Ellipse>
</VisualBrush.Visual>
<VisualBrush.Transform>
<ScaleTransform ScaleX="{Binding Path=IrisSize,
RelativeSource={RelativeSource TemplatedParent}}"
ScaleY="{Binding Path=IrisSize, RelativeSource=
{RelativeSource TemplatedParent}}" CenterX=".5"
CenterY=".5"/>
</VisualBrush.Transform>
</VisualBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
<!--Pupil-->
<DiffuseMaterial>
<DiffuseMaterial.Brush>
<VisualBrush Stretch="None" Opacity="1">
<VisualBrush.Visual>
<Ellipse Width=".016" Height="0.029"
Fill="{Binding Path=PupilColor,
RelativeSource={RelativeSource TemplatedParent}}"/>
</VisualBrush.Visual>
<VisualBrush.Transform>
<ScaleTransform ScaleX="{Binding Path=PupilSize,
RelativeSource={RelativeSource TemplatedParent}}"
ScaleY="{Binding Path=PupilSize, RelativeSource=
{RelativeSource TemplatedParent}}" CenterY=".5"
CenterX=".5" />
</VisualBrush.Transform>
</VisualBrush>
</DiffuseMaterial.Brush>
</DiffuseMaterial>
<!-- Light reflex-->
<SpecularMaterial SpecularPower="100">
<SpecularMaterial.Brush>
<SolidColorBrush Color="#DBDBDB" Opacity="1.000000"/>
</SpecularMaterial.Brush>
</SpecularMaterial>
<EmissiveMaterial Brush="#05FF0000" />
</MaterialGroup>
</GeometryModel3D.Material>
<!-- Transformation -->
<GeometryModel3D.Transform>
<Transform3DGroup>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Axis="1,0,0"
Angle="{Binding Path=RotationXAxis,
RelativeSource={RelativeSource TemplatedParent}}"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
<RotateTransform3D>
<RotateTransform3D.Rotation>
<AxisAngleRotation3D Axis="0,1,0"
Angle="{Binding Path=RotationYAxis,
RelativeSource={RelativeSource TemplatedParent}}"/>
</RotateTransform3D.Rotation>
</RotateTransform3D>
</Transform3DGroup>
</GeometryModel3D.Transform>
</GeometryModel3D>
<!-- Lights -->
<AmbientLight Color="#FF646464" />
<SpotLight InnerConeAngle="29"
OuterConeAngle="31" Color="#666666"
Direction=".94,1.2,3.1" Position="-2,-0.8,-8"
Range="20"/>
<DirectionalLight Color="#CC666666"
Direction="1,-1,1"/>
<DirectionalLight Color="#FF444444"
Direction="0,1,5"/>
</Model3DGroup>
</ModelVisual3D.Content>
</ModelVisual3D>
</Viewport3D.Children>
</Viewport3D>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
看点
工具箱位图
设置工具箱位图图标非常简单,将以下属性添加到类中
namespace EyeControl
{
[ToolboxBitmap(typeof(Eye))]
public class Eye : Control
{...
将位图添加到资源中,文件名为:namespace.class.icon.bmp(资源名称不重要)。 在示例中,我使用文件:EyeControl.Eye.icon.bmp。

眼睛和眼球……眼球(哈哈)
属性分类
设置属性的类别属性与 WPF 和 Windows Forms 相同,这是一个例子
[Category("Eye"), Browsable(true)]
[Description("The size of the pupil (0-5).")]
public double PupilSize
{
get { return (double)GetValue(PupilSizeProperty); }
set { SetValue(PupilSizeProperty, value); }
}
已分类的属性。
哦…
我花了一些时间才弄清楚,将依赖属性的默认值转换为其值类型是完全多余的。
摘要
使用 WPF 创建 Eye
自定义控件并不容易,但可能性似乎是无限的,而且性能很好。
我面临的大多数困难源于层之间的分离,即用法(XAML)、代码隐藏(C#)和样式(XAML)都必须结合起来才能形成控件。
历史
这是第一个版本。