WPF开发冷风机组态及应用

Posted inet_ygssoftware

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了WPF开发冷风机组态及应用相关的知识,希望对你有一定的参考价值。

冷风机组件开发和应用

VS2022

.NET6框架

冷风机组件开发演示

WPF主界面设计

WPF主界面托板设计

<Window x:Class="WpfConsolePannel.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:WpfConsolePannel"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="1260">
    <Grid Background="Black">
        <Canvas Background="Transparent"
                MouseWheel="Canvas_MouseWheel"
                MouseLeftButtonDown="Canvas_MouseLeftButtonDown"
                MouseLeftButtonUp="Canvas_MouseLeftButtonUp"
                MouseMove="Canvas_MouseMove">
            <Viewbox Canvas.Left="30" Canvas.Top="120" Name="mainView">
                <Grid>
                    <Polygon VerticalAlignment="Center" 
                             Fill="LightGray" 
                             Points="0,200 150,0 1000,0 1200 200 0,200"
                             Stroke="LightGray"
                             StrokeThickness="2"/>
                    
                </Grid>
            </Viewbox>
        </Canvas>
    </Grid>
</Window>

WPF托板拖动实现

/// <summary>
/// 视图缩放
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)

    // 获取实际渲染的高度和宽度
    var w = this.mainView.ActualWidth + e.Delta;
    var h = this.mainView.ActualHeight + e.Delta;
    if (w <100) w = 500;
    if (h <100) h = 100;
    this.mainView.Height = h;
    this.mainView.Width = w;
    // 设置画板缩放的左边位置
    this.mainView.SetValue(Canvas.LeftProperty, (this.RenderSize.Width - this.mainView.Width) / 2);


bool _isMoving = false;
Point _point = new Point(0, 0);
double _left =0, _top = 0;

private void Canvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)

    _isMoving = true;
    _point = e.GetPosition(sender as Canvas);
    _left = double.Parse(this.mainView.GetValue(Canvas.LeftProperty).ToString()!);
    _top = double.Parse(this.mainView.GetValue(Canvas.TopProperty).ToString()!);


private void Canvas_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)

    _isMoving = false;


private void Canvas_MouseMove(object sender, MouseEventArgs e)

    if (_isMoving)
    
        Point currentPoint = e.GetPosition(sender as Canvas);
        this.mainView.SetValue(LeftProperty, _left + (currentPoint.X - _point.X));
        this.mainView.SetValue(TopProperty, _top+(currentPoint.Y - _point.Y));
    

冷风机自定义控件

初始化代码

<Border BorderThickness="1" Name="frame">
    <Viewbox VerticalAlignment="Center" HorizontalAlignment="Center">
        <Canvas Width="205" Height="245" Margin="5">
           
        </Canvas>
    </Viewbox>
</Border>

画风扇托板

<Polygon Points="0,70 40,10 205,10 180,70" Fill="#FFF" />

画风扇上座弧形

<Path Canvas.Left="50" Canvas.Top="20" Data="M0 0A60 15 0 0 0 120 0L120 25A60 15 0 0 1 0 25">
    <Path.Fill>
        <LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
            <GradientStop Color="#FFD6D6D6" Offset="0" />
            <GradientStop Color="#FFFFFF" Offset="0.5" />
            <GradientStop Color="#FFD6D6D6" Offset="1" />
        </LinearGradientBrush>
    </Path.Fill>
</Path>
<Ellipse Width="120" Height="30" Fill="#CCC" Canvas.Top="10" Canvas.Left="50" />

通过Path画风扇

<Border Canvas.Left="54" Canvas.Top="-30" >
    <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 Fill="White" Data="M240.16436182 107.8387919c-64.76383717 88.95385497-39.00023321 207.2195934 60.99957411 287.22561045 41.74629367 33.41554783 139.52456881 68.55895483 127.98494279 96.5132357-52.94651971 81.57960187-156.4946072 17.15516602-220.88818912-41.00578317-84.01711628-75.80978886-156.21691576-56.74163671-186.48529261 51.09524212C-10.71451204 617.03250262 48.74233051 765.65918238 143.5585623 806.54154713c97.59314685 42.05484037 202.8073843-5.33784855 283.36878357-128.54032568 20.48746395-31.40999788 29.68213938-91.08282334 81.3019111-61.30811948 38.50655955 22.21532312 28.4171006 72.53919947 5.52297551 110.61379388-18.29678704 30.39179594-36.68613723 61.3698287-59.30256954 88.55274511-78.77183221 94.56939496-53.77959402 163.86885964 69.20690087 187.44178602C645.74827583 1026.59666126 777.09637117 968.06545617 807.88927696 868.96043369c39.37048913-126.50392112-28.54051901-207.80583155-128.046652-271.21206545-32.11965444-20.45661001-92.37871738-31.16316105-60.38248135-83.02976894 21.50566722-34.77315109 71.15074161-22.83241521 111.81712478-4.75161041 34.06349519 15.11876146 60.99957344 36.25417276 88.02821618 60.69102741 85.34386493 77.32166513 152.4526527 57.11189197 183.18384861-53.16250194 32.27392681-115.82822468-30.42265054-264.8560143-126.93588558-301.81984297-108.85508144-41.71543973-239.2466847 3.45571702-303.3317199 145.35609104-15.36559829 22.15361392-16.10610946 68.0652805-47.73208892 56.30967159-30.23752292-11.29278919-32.67503733-45.69568436-28.20111769-70.65706794 10.55227868-58.50034983 37.79690298-106.29414861 87.5345425-146.5902752 61.80179382-50.07704018 57.54385709-108.33055316-11.13851617-155.84665985-89.57094706-61.86350302-265.53481626-28.38624599-332.5201856 63.52965167z m304.56590408 376.82741277a41.84597906 41.84597906 0 1 1-59.17915112 59.17915112 41.84597906 41.84597906 0 0 1 59.17915112-59.17915112z" />
    </Viewbox>
</Border>

画外壳

<Grid Width="180" Height="180" Background="LightGray" Canvas.Top="70">
    <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="45" Margin="5">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Border Background="#AAA" Margin="2" />
        <Border Background="#AAA" Margin="2" Grid.Column="1" />
    </Grid>
</Grid>
<Grid Width="180" Height="180" Background="LightGray" Canvas.Top="70" Canvas.Left="180">
    <Grid.ColumnDefinitions>
        <ColumnDefinition Width="29*"/>
        <ColumnDefinition Width="7*"/>
    </Grid.ColumnDefinitions>
    <Grid.RenderTransform>
        <TransformGroup>
            <ScaleTransform ScaleX="0.139" />
            <SkewTransform AngleY="-67.4" />
        </TransformGroup>
    </Grid.RenderTransform>
    <Border VerticalAlignment="Top" Height="140" BorderThickness="10" Grid.ColumnSpan="2">
        <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="45" Margin="5,0,5,5" Grid.ColumnSpan="2">
        <Grid.ColumnDefinitions>
            <ColumnDefinition />
            <ColumnDefinition />
        </Grid.ColumnDefinitions>
        <Border Background="#AAA" Margin="2" />
        <Border Background="#AAA" Margin="2" Grid.Column="1" />
    </Grid>
</Grid>

画指示灯

<Border Width="18" Height="18" CornerRadius="10" Canvas.Left="155" Canvas.Top="85">
    <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="155" Canvas.Top="110">
    <Border.Background>
        <RadialGradientBrush>
            <GradientStop Color="gray" Offset="0.5" x:Name="gsRed" />
            <GradientStop Color="White" />
        </RadialGradientBrush>
    </Border.Background>
</Border>

VisualStateManager设置运行状态

<VisualStateManager.VisualStateGroups>
    <VisualStateGroup>
        <VisualState Name="RunState">
            <Storyboard>
                <!--添加风扇旋转动画-->
                <DoubleAnimation Duration="0:0:0.1" From="0" To="-360" 
                                 RepeatBehavior="Forever"
                                 Storyboard.TargetName="rt"
                                 Storyboard.TargetProperty="Angle"/>
                <ColorAnimationUsingKeyFrames Storyboard.TargetName="gsGreen"
                                              Storyboard.TargetProperty="Color">
                    <DiscreteColorKeyFrame Value="Green" KeyTime="0" />
                </ColorAnimationUsingKeyFrames>
            </Storyboard>
        </VisualState>
        <VisualState Name="StopState" />
    </VisualStateGroup>
    <VisualStateGroup>
        <VisualState Name="FaultState">
            <Storyboard>
                <!--错误指示灯-->
                <ColorAnimationUsingKeyFrames Storyboard.TargetName="gsRed"
                                              Storyboard.TargetProperty="Color"
                                              RepeatBehavior="Forever">
                    <DiscreteColorKeyFrame Value="Red" KeyTime="0:0:0.5" />
                    <DiscreteColorKeyFrame Value="Gray" KeyTime="0:0:1" />
                </ColorAnimationUsingKeyFrames>
            </Storyboard>
        </VisualState>
        <VisualState Name="NormalState" />
    </VisualStateGroup>
</VisualStateManager.VisualStateGroups>

添加依赖属性

public bool IsRunning

    get  return (bool)GetValue(IsRunningProperty); 
    set  SetValue(IsRunningProperty, value); 


// Using a DependencyProperty as the backing store for IsRunning.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsRunningProperty =
    DependencyProperty.Register("IsRunning", typeof(bool), typeof(CoolingTower), new PropertyMetadata(default(bool),new PropertyChangedCallback(OnRunStateChanged))); 

private static void OnRunStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

    bool state = (bool)e.NewValue;
    VisualStateManager.GoToState(d as CoolingTower, state ? "RunState" : "StopState", false);


public bool IsFault

    get  return (bool)GetValue(IsFaultProperty); 
    set  SetValue(IsFaultProperty, value); 


// Using a DependencyProperty as the backing store for IsRunning.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty IsFaultProperty =
    DependencyProperty.Register("IsFault", typeof(bool), typeof(CoolingTower), new PropertyMetadata(default(bool), new PropertyChangedCallback(OnFaultStateChanged)));

private static void OnFaultStateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

    bool state = (bool)e.NewValue;
    VisualStateManager.GoToState(d as CoolingTower, state ? "FaultState" : "NormalState", false);

自定义流动管道控件

窗口布局

<UserControl x:Class="WpfComponent.Controls.Pipeline"
             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:WpfComponent.Controls"
             mc:Ignorable="d" 
             d:DesignHeight="30" d:DesignWidth="500">
    <Grid>
        <VisualStateManager.VisualStateGroups>
            <VisualStateGroup>
                <VisualState Name="WEFlowState">
                    <Storyboard RepeatBehavior="Forever">
                        <DoubleAnimation Duration="0:0:1" From="0" To="5"
                                         Storyboard.TargetName="flowLine"
                                         Storyboard.TargetProperty="StrokeDashOffset"
                                         />
                    </Storyboard>
                </VisualState>
                <VisualState Name="EEFlowState">
                    <Storyboard RepeatBehavior="Forever">
                        <DoubleAnimation Duration="0:0:1" From="0" To="-5"
                                         Storyboard.TargetName="flowLine"
                                         Storyboard.TargetProperty="StrokeDashOffset"
                                         />
                    </Storyboard>
                </VisualState>
            </VisualStateGroup>
        </VisualStateManager.VisualStateGroups>
        <Border CornerRadius="Binding CapRadius, RelativeSource=RelativeSource AncestorType=UserControl,Mode=FindAncestor">
            <Border.Background>
                <LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
                    <GradientStop Color="#FFCBCBCB" Offset="0.9"/>
                    <GradientStop Color="#FFFFFFFF" Offset="0.5"/>
                    <GradientStop Color="#FFCBCBCB" Offset="0.0"/>
                </LinearGradientBrush>
            </Border.Background>
            <Border Margin="2" Name="border">
                <Line X1="0" Y1="0" X2="Binding RelativeSource=RelativeSource Self,Path=ActualWidth"
                      Y2="0" 
                      Stroke="Binding LiquidColor,RelativeSource=RelativeSource AncestorType=UserControl,Mode=FindAncestor"
                      StrokeThickness="Binding ElementName=border,Path=ActualHeight"
                      StrokeDashArray="2,3"
                      VerticalAlignment="Center"
                      Stretch="Fill"
                      StrokeDashCap="Round"
                      StrokeEndLineCap="Round"
                      StrokeStartLineCap="Round"
                      Name="flowLine" Opacity="0.3"
                      />
            </Border>
        </Border>      
    </Grid>
</UserControl>

自定义依赖属性

public int Direction

    get  return (int)GetValue(DirectionProperty); 
    set  SetValue(DirectionProperty, value); 


// Using a DependencyProperty as the backing store for Direction.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty DirectionProperty =
    DependencyProperty.Register("Direction", typeof(int), typeof(Pipeline), new PropertyMetadata(default(int),new PropertyChangedCallback(OnDirectionChanged)));

/// <summary>
/// 设置状态
/// </summary>
/// <param name="d"></param>
/// <param name="e"></param>
/// <exception cref="NotImplementedException"></exception>
private static void OnDirectionChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

    int value = int.Parse(e.NewValue.ToString()!);
    VisualStateManager.GoToState(d as Pipeline, value == 1 ? "WEFlowState" : "EEFlowState",false);



/// <summary>
/// 设置液体颜色
/// </summary>
public Brush LiquidColor

    get  return (Brush)GetValue(LiquidColorProperty); 
    set  SetValue(LiquidColorProperty, value); 


// Using a DependencyProperty as the backing store for LiquidColor.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty LiquidColorProperty =
    DependencyProperty.Register("LiquidColor", typeof(Brush), typeof(Pipeline), new PropertyMetadata(Brushes.Red));



public int CapRadius

    get  return (int)GetValue(CapRadiusProperty); 
    set  SetValue(CapRadiusProperty, value); 


// Using a DependencyProperty as the backing store for CapRadius.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty CapRadiusProperty =
    DependencyProperty.Register("CapRadius", typeof(int), typeof(Pipeline), new PropertyMetadata(0));

界面组装组态应用

<component:CoolingTower Width="90" Height="110" HorizontalAlignment="Left" VerticalAlignment="Bottom"
                        Margin="125 0 0 100"
                        IsRunning="False"
                        IsFault="False" />
<component:CoolingTower Width="90" Height="110" HorizontalAlignment="Left" VerticalAlignment="Bottom"
                        Margin="100 0 0 60"
                        IsRunning="False"
                        IsFault="False" />
<component:CoolingTower Width="90" Height="110" HorizontalAlignment="Left" VerticalAlignment="Bottom"
                        Margin="75 0 0 10"
                        IsRunning="False"
                        IsFault="False" />

<component:Pipeline Height="10" 
                    LiquidColor="Green"
                    Direction="1"
                    CapRadius="2"
                    Width="200"
                    VerticalAlignment="Top" Margin="207,53,805,0"/>
<component:Pipeline Height="10" 
                    LiquidColor="Red"
                    Direction="1"
                    CapRadius="2"
                    Width="200"
                    VerticalAlignment="Top" Margin="180,97,832,0"/>
<component:Pipeline Height="10" 
                    LiquidColor="Orange"
                    Direction="1"
                    CapRadius="2"
                    Width="210"
                    VerticalAlignment="Top" Margin="150,146,852,0"/>
<component:Pipeline Height="10" 
                    LiquidColor="Orange"
                    Direction="1"
                    CapRadius="2"
                    Width="150"
                    VerticalAlignment="Top" Margin="352,149,710,0">
    <component:Pipeline.RenderTransform>
        <RotateTransform Angle="-60" />
    </component:Pipeline.RenderTransform>
</component:Pipeline>
<component:Pipeline Height="10" 
                    LiquidColor="Orange"
                    Direction="1"
                    CapRadius="2"
                    Width="210"
                    VerticalAlignment="Top" Margin="429,20,573,0"/>
<component:Pipeline Height="10" 
                    LiquidColor="Orange"
                    Direction="-1"
                    CapRadius="2"
                    Width="150"
                    VerticalAlignment="Top" Margin="556,151,506,0">
    <component:Pipeline.RenderTransform>
        <RotateTransform Angle="-60" />
    </component:Pipeline.RenderTransform>
</component:Pipeline>

以上是关于WPF开发冷风机组态及应用的主要内容,如果未能解决你的问题,请参考以下文章

WPF开发冷风机组态及应用

WPF控制动画开始停止暂停和恢复

MM32 SPIN MCU 电机 FOC 驱动 风机无传感器弦波驱动篇应用笔记

行业案例 | 要实现风机的AR运维管理,总共分几步?

涂鸦智能暖风机软件实现之暖风机外设驱动实现

风机的分类种类