前言
在工业应用中,冷却塔是关键组件,用于有效散热和设备管理。WPF作为一种强大的UI框架,能够创建美观且功能丰富的监控界面。
本文将简要介绍如何在WPF中创建一个冷却塔组件,涵盖图形绘制、动画效果和数据绑定等核心功能。通过本文快速掌握这一技能,并应用于实际项目中。
1、封装基类ComponentBase.cs 继承自UserControl,定义组件中使用的属性和命令
public class ComponentBase : UserControl
{
private bool _isSelected;
public bool IsSelected
{
get { return _isSelected; }
set
{
_isSelected = value;
if (value)
{
var parent = VisualTreeHelper.GetParent(this) as Grid;
if (parent != null)
{
foreach (var item in parent.Children)
{
if (item is ComponentBase)
(item as ComponentBase).IsSelected = false;
}
}
}
VisualStateManager.GoToState(this, value ? "Selected" : "Unselected", false);
}
}
public bool IsRunning
{
get { return (bool)GetValue(IsRunningProperty); }
set { SetValue(IsRunningProperty, value); }
}
public static readonly DependencyProperty IsRunningProperty =
DependencyProperty.Register("IsRunning", typeof(bool), typeof(ComponentBase), new PropertyMetadata(default(bool), new PropertyChangedCallback(OnRunningChanged)));
private static void OnRunningChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
VisualStateManager.GoToState(d as ComponentBase, (bool)e.NewValue ? "RunState" : "Stop", false);
}
public bool IsFaultState
{
get { return (bool)GetValue(IsFaultStateProperty); }
set { SetValue(IsFaultStateProperty, value); }
}
public static readonly DependencyProperty IsFaultStateProperty =
DependencyProperty.Register("IsFaultState", typeof(bool), typeof(ComponentBase), new PropertyMetadata(default(bool), new PropertyChangedCallback(OnFaultStateChanged)));
private static void OnFaultStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
VisualStateManager.GoToState(d as ComponentBase, (bool)e.NewValue ? "FaultState" : "NormalState", false);
}
public ICommand Command
{
get { return (ICommand)GetValue(CommandProperty); }
set { SetValue(CommandProperty, value); }
}
public static readonly DependencyProperty CommandProperty =
DependencyProperty.Register("Command", typeof(ICommand), typeof(ComponentBase), new PropertyMetadata(default(ICommand)));
public object CommandParameter
{
get { return (object)GetValue(CommandParameterProperty); }
set { SetValue(CommandParameterProperty, value); }
}
public static readonly DependencyProperty CommandParameterProperty =
DependencyProperty.Register("CommandParameter", typeof(object), typeof(ComponentBase), new PropertyMetadata(default(object)));
public ComponentBase()
{
this.PreviewMouseLeftButtonDown += ComponentBase_PreviewMouseLeftButtonDown;
}
private void ComponentBase_PreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
this.IsSelected = !this.IsSelected;
this.Command?.Execute(this.CommandParameter);
e.Handled = true;
}
}
2、编写设计冷却塔组件 CoolingTower.xaml,使用local:ComponentBase节点包裹,绑定基础组件类中的上下文
<local:ComponentBase x:Class="Wpf.Industrial.Controls.CoolingTower"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Wpf.Industrial.Controls"
mc:Ignorable="d" Cursor="Hand"
d:DesignHeight="450" d:DesignWidth="800">
<Border BorderThickness="1" x:Name="frame">
<VisualStateManager.VisualStateGroups>
<VisualStateGroup Name="SelectStateGroup">
<VisualState Name="Selected">
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(Border.BorderBrush)" Storyboard.TargetName="frame">
<DiscreteObjectKeyFrame KeyTime="0">
<DiscreteObjectKeyFrame.Value>
<SolidColorBrush Color="Orange"/>
</DiscreteObjectKeyFrame.Value>
</DiscreteObjectKeyFrame>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState Name="Unselected"/>
</VisualStateGroup>
<VisualStateGroup Name="RunStateGroup">
<VisualState Name="RunState">
<Storyboard>
<DoubleAnimation Duration="00:0:0.5" From="0" To="-360" RepeatBehavior="Forever"
Storyboard.TargetProperty="(RotateTransform.Angle)"
Storyboard.TargetName="rt"/>
<ColorAnimationUsingKeyFrames
Storyboard.TargetName="gsGreen"
Storyboard.TargetProperty="Color">
<DiscreteColorKeyFrame Value="Green" KeyTime="0"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState Name="Stop"/>
</VisualStateGroup>
<VisualStateGroup x:Name="FaultStateGroup">
<VisualState Name="FaultState">
<Storyboard>
<ColorAnimationUsingKeyFrames RepeatBehavior="Forever"
Storyboard.TargetName="gsRed1"
Storyboard.TargetProperty="Color">
<DiscreteColorKeyFrame Value="Red" KeyTime="0:0:0.5"/>
<DiscreteColorKeyFrame Value="Gray" KeyTime="0:0:1"/>
</ColorAnimationUsingKeyFrames>
</Storyboard>
</VisualState>
<VisualState Name="NormalState"/>
</VisualStateGroup>
</VisualStateManager.VisualStateGroups>
<Viewbox VerticalAlignment="Center" HorizontalAlignment="Center">
<Canvas Width="205" Height="245" Margin="5">
<Polygon Points="0,65 40,10 205,10 180,65" Fill="#EEE"/>
<Path Data="M0 0A60 15 0 0 0 120 0L120 25A60 15 0 0 1 0 25" Canvas.Left="45"
HorizontalAlignment="Center" Margin="0,15,0,0">
<Path.Fill>
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
<GradientStop Color="#FFD6D6D6" Offset="0"/>
<GradientStop Color="White" Offset="0.519"/>
<GradientStop Color="#FFD6D6D6" Offset="1"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
<Ellipse Width="120" Height="30" Fill="#CCC" VerticalAlignment="Top" Canvas.Left="45"/>
<Border VerticalAlignment="Top" Canvas.Left="50" Canvas.Top="-40">
<Viewbox Width="110" Height="110" RenderTransformOrigin="0.5,0.5">
<Viewbox.RenderTransform>
<TransformGroup>
<RotateTransform Angle="0" x:Name="rt"/>
<ScaleTransform ScaleY="0.25"/>
</TransformGroup>
</Viewbox.RenderTransform>
<Path Data="M605.61792 481.6c110.464-39.808 281.6-67.584 376.192 33.536 92.672 98.944 31.168 350.016-167.232 395.904-186.496 43.136-27.456-356.736-246.912-313.6a108.224 108.224 0 0 1-22.4 15.104c38.4 110.592 62.656 276.416-36.224 369.024s-350.08 31.168-395.968-167.232c-41.344-178.816 325.248-39.424 317.44-220.992a107.648 107.648 0 0 1-30.592-44.8c-110.592 36.288-268.032 55.616-357.504-39.68C-50.44608 409.984 11.18592 159.04 210.03392 113.152c179.2-41.28 40.128 323.648 220.608 317.184a107.584 107.584 0 0 1 46.848-23.04c-37.376-110.784-59.648-273.472 37.824-364.8C614.44992-50.496 865.20192 11.136 911.08992 209.984c43.456 188.48-363.328 24.832-312.256 252.928a106.304 106.304 0 0 1 6.784 18.688z" Fill="#EEE">
</Path>
</Viewbox>
</Border>
<Grid Grid.Row="1" Width="180" Height="180" Background="LightGray" Canvas.Top="65">
<Border VerticalAlignment="Top" Height="140" BorderThickness="10">
<Border.Background>
<DrawingBrush TileMode="Tile" ViewportUnits="Absolute" Viewport="1,0,25,1">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="#EEE"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure>
<LineSegment Point="10,0"/>
<LineSegment Point="10,10"/>
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Border.Background>
</Border>
<Grid VerticalAlignment="Bottom" Height="40" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Background="#FFAAAAAA" Margin="2"/>
<Border Background="#FFAAAAAA" Margin="2" Grid.Column="1"/>
</Grid>
</Grid>
<Grid Grid.Row="1" Width="180" Height="180" Background="LightGray" Canvas.Top="65" Canvas.Left="180">
<Grid.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="0.139"/>
<SkewTransform AngleY="-65.5"/>
</TransformGroup>
</Grid.RenderTransform>
<Border VerticalAlignment="Top" Height="140" BorderThickness="10">
<Border.Background>
<DrawingBrush TileMode="Tile" ViewportUnits="Absolute" Viewport="1,0,25,1">
<DrawingBrush.Drawing>
<GeometryDrawing>
<GeometryDrawing.Pen>
<Pen Brush="#EEE"/>
</GeometryDrawing.Pen>
<GeometryDrawing.Geometry>
<PathGeometry>
<PathFigure>
<LineSegment Point="10,0"/>
<LineSegment Point="10,10"/>
</PathFigure>
</PathGeometry>
</GeometryDrawing.Geometry>
</GeometryDrawing>
</DrawingBrush.Drawing>
</DrawingBrush>
</Border.Background>
</Border>
<Grid VerticalAlignment="Bottom" Height="40" Margin="5">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Border Background="#FFAAAAAA" Margin="2"/>
<Border Background="#FFAAAAAA" Margin="2" Grid.Column="1"/>
</Grid>
</Grid>
<Border Width="18" Height="18" CornerRadius="10" Canvas.Left="150" Canvas.Top="80">
<Border.Background>
<RadialGradientBrush>
<GradientStop Color="Gray" Offset="0.5" x:Name="gsGreen"/>
<GradientStop Color="White"/>
</RadialGradientBrush>
</Border.Background>
</Border>
<Border Width="18" Height="18" CornerRadius="10" Canvas.Left="150" Canvas.Top="105">
<Border.Background>
<RadialGradientBrush>
<GradientStop Color="Gray" Offset="0.6" x:Name="gsRed1"/>
<GradientStop Color="White"/>
</RadialGradientBrush>
</Border.Background>
</Border>
</Canvas>
</Viewbox>
</Border>
</local:ComponentBase>
后台代码继承ComponentBase基类
/// <summary>
/// CoolingTower.xaml 的交互逻辑
/// </summary>
public partial class CoolingTower : ComponentBase
{
public CoolingTower()
{
InitializeComponent();
}
}
3.使用该组件
<!--冷却塔-->
<control:CoolingTower Width="90" Height="110" Command="{Binding ComponentCommand}"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
Margin="125,0,0,95"/>
最后
如果你觉得这篇文章对你有帮助,不妨点个赞支持一下!你的支持是我继续分享知识的动力。如果有任何疑问或需要进一步的帮助,欢迎随时留言。
也可以加入微信公众号 [DotNet技术匠] 社区,与其他热爱技术的同行一起交流心得,共同成长!
优秀是一种习惯,欢迎大家留言学习!
作者:江渔湖
出处:cnblogs.com/jiangyuhu/p/18673261
声明:网络内容,仅供学习,尊重版权,侵权速删,歉意致谢!