WPF開發經驗-實現一種機械泵控制項

来源:https://www.cnblogs.com/wwwen/archive/2023/01/28/17070859.html
-Advertisement-
Play Games

一 引入 考慮實現一種機械泵控制項。 機械泵是工業中通常用來製造真空的一類設備,我們在繪製界面UI時希望可以生動形象地來表述一個機械泵,下麵講述了一種簡單的實現。 二 MechanicalPumpControl 聲明一個MechanicalPumpControl的自定義控制項,它繼承自Control類。 ...


一 引入

考慮實現一種機械泵控制項。

機械泵是工業中通常用來製造真空的一類設備,我們在繪製界面UI時希望可以生動形象地來表述一個機械泵,下麵講述了一種簡單的實現。

二 MechanicalPumpControl

聲明一個MechanicalPumpControl的自定義控制項,它繼承自Control類。

對於一個MechanicalPump來說,它具有狀態,這裡定義一個State依賴屬性來簡單描述泵的狀態,State等於0表示泵停止狀態,State等於1表示泵運行狀態。

State可以綁定到實際的泵狀態數據源,當泵狀態數據變化時,MechanicalPumpControl需要相應動態顯示泵狀態動畫。

定義StartAnimation和StopAnimation兩個依賴屬性,來啟動和停止泵狀態動畫。

關於控制項的狀態切換也可以考慮用VisualStateManager來實現,可以更方便地管理控制項的狀態以及用於狀態過渡的邏輯,推薦用這種方式。

public class MechanicalPumpControl : Control
{
    static MechanicalPumpControl()
    {
        DefaultStyleKeyProperty.OverrideMetadata(typeof(MechanicalPumpControl), new FrameworkPropertyMetadata(typeof(MechanicalPumpControl)));
    }

   
    public static readonly DependencyProperty StateProperty = DependencyProperty.Register(
    "State",
    typeof(int),
    typeof(MechanicalPumpControl), new PropertyMetadata(PropertyChangedCallback));

    public int State
    {
        get => (int)GetValue(StateProperty);
        set => SetValue(StateProperty, value);
    }

    private static void PropertyChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var pumpControl = d as MechanicalPumpControl;

        if ((int)e.OldValue == 0 && (int)e.NewValue == 1)
        {
            pumpControl.StopAnimation = false;
            pumpControl.StartAnimation = true;
        }
        else if ((int)e.OldValue == 1 && (int)e.NewValue == 0)
        {
            pumpControl.StopAnimation = true;
            pumpControl.StartAnimation = false;
        }
    }

    public static readonly DependencyProperty StartAnimationProperty = DependencyProperty.Register(
        "StartAnimation",
        typeof(bool),
        typeof(MechanicalPumpControl));

    public bool StartAnimation
    {
        get => (bool)GetValue(StartAnimationProperty);
        set => SetValue(StartAnimationProperty, value);
    }

    public static readonly DependencyProperty StopAnimationProperty = DependencyProperty.Register(
        "StopAnimation",
        typeof(bool),
        typeof(MechanicalPumpControl));

    public bool StopAnimation
    {
        get => (bool)GetValue(StopAnimationProperty);
        set => SetValue(StopAnimationProperty, value);
    }
}

 

三 Style

接下來編寫MechanicalPumpControl的樣式。

考慮繪製出不動的泵體部分,和動作的扇葉部分。當泵停止狀態時,扇葉靜止,當泵運轉狀態時,扇葉轉動。

樣式代碼如下:

 <Style TargetType="{x:Type Rectangle}" x:Key="FanRec">
     <Setter Property="Canvas.Left" Value="7"/>
     <Setter Property="Width" Value="48"/>
     <Setter Property="Height" Value="6"/>
     <Setter Property="RadiusX" Value="0.5"/>
     <Setter Property="RadiusY" Value="0.5"/>
     <Setter Property="Fill" Value="SlateGray"/>
     <Setter Property="RenderTransform">
         <Setter.Value>
             <SkewTransform AngleX="-20" AngleY="-7"/>
         </Setter.Value>
     </Setter>
 </Style>

 <Style TargetType="{x:Type local:MechanicalPumpControl}">
     <Setter Property="Template">
         <Setter.Value>
             <ControlTemplate TargetType="{x:Type local:MechanicalPumpControl}">
                 <Viewbox Stretch="Fill">
                     <Canvas Width="180" Height="100">
                         <Rectangle Width="60" Height="60" Canvas.Top="10" Stroke="Gray"  StrokeThickness="3" RadiusX="3" RadiusY="3" />
                         <Canvas  Width="60" Height="54" Canvas.Top="14" ClipToBounds="True">
                             <Canvas x:Name="canvas1" Width="60" Height="54">
                                 <Rectangle x:Name="rec1" Style="{StaticResource FanRec}" Canvas.Top="6"/>
                                 <Rectangle x:Name="rec2" Style="{StaticResource FanRec}" Canvas.Top="16"/>
                                 <Rectangle x:Name="rec3" Style="{StaticResource FanRec}" Canvas.Top="26"/>
                                 <Rectangle x:Name="rec4" Style="{StaticResource FanRec}" Canvas.Top="36"/>
                                 <Rectangle x:Name="rec5" Style="{StaticResource FanRec}" Canvas.Top="46"/>
                             </Canvas>
                             <Canvas x:Name="canvas2" Width="60" Height="54">
                                 <Rectangle x:Name="rec6" Style="{StaticResource FanRec}" Canvas.Top="56"/>
                                 <Rectangle x:Name="rec7" Style="{StaticResource FanRec}" Canvas.Top="66"/>
                                 <Rectangle x:Name="rec8" Style="{StaticResource FanRec}" Canvas.Top="76"/>
                                 <Rectangle x:Name="rec9" Style="{StaticResource FanRec}" Canvas.Top="86"/>
                                 <Rectangle x:Name="rec10" Style="{StaticResource FanRec}" Canvas.Top="96"/>
                                 <Rectangle x:Name="rec11" Style="{StaticResource FanRec}" Canvas.Top="106"/>
                             </Canvas>
                         </Canvas>
                         <Rectangle  Width="5" Height="40" Canvas.Left="60" Canvas.Top="20"  Stroke="Gray"  StrokeThickness="4"/>
                         <Rectangle  Width="110" Height="82" Canvas.Left="65"  RadiusX="3" RadiusY="3" Stroke="Gray"  StrokeThickness="4"/>
                         <Rectangle  Width="10" Height="8" Canvas.Left="75" Canvas.Top="82" Fill="Gray" />
                         <Rectangle  Width="10" Height="8" Canvas.Left="155" Canvas.Top="82" Fill="Gray" />
                         <Rectangle  Width="140" Height="10" Canvas.Left="40" Canvas.Top="90" Fill="Black" RadiusX="2" RadiusY="2"/>
                     </Canvas>
                 </Viewbox>
                 <ControlTemplate.Triggers>
                     <Trigger Property="StartAnimation" Value="true">
                         <Trigger.EnterActions>
                             <BeginStoryboard Name="moveStory">
                                 <Storyboard RepeatBehavior="Forever" SpeedRatio="4">
                                     <DoubleAnimationUsingKeyFrames 
                                                 Storyboard.TargetName="canvas1" 
                                                 Storyboard.TargetProperty="(Canvas.Top)" 
                                                 Duration="0:0:6" >
                                         <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
                                         <LinearDoubleKeyFrame Value="-10" KeyTime="0:0:1"/>
                                         <LinearDoubleKeyFrame Value="-20" KeyTime="0:0:2"/>
                                         <LinearDoubleKeyFrame Value="-30" KeyTime="0:0:3"/>
                                         <LinearDoubleKeyFrame Value="-40" KeyTime="0:0:4"/>
                                         <LinearDoubleKeyFrame Value="-50" KeyTime="0:0:5"/>
                                         <LinearDoubleKeyFrame Value="-60" KeyTime="0:0:6"/>
                                     </DoubleAnimationUsingKeyFrames>
                                     <DoubleAnimationUsingKeyFrames 
                                                 Storyboard.TargetName="canvas2" 
                                                 Storyboard.TargetProperty="(Canvas.Top)" 
                                                 Duration="0:0:6" >
                                         <LinearDoubleKeyFrame Value="0" KeyTime="0:0:0"/>
                                         <LinearDoubleKeyFrame Value="-10" KeyTime="0:0:1"/>
                                         <LinearDoubleKeyFrame Value="-20" KeyTime="0:0:2"/>
                                         <LinearDoubleKeyFrame Value="-30" KeyTime="0:0:3"/>
                                         <LinearDoubleKeyFrame Value="-40" KeyTime="0:0:4"/>
                                         <LinearDoubleKeyFrame Value="-50" KeyTime="0:0:5"/>
                                         <LinearDoubleKeyFrame Value="-60" KeyTime="0:0:6"/>
                                     </DoubleAnimationUsingKeyFrames>
                                 </Storyboard>
                             </BeginStoryboard>
                         </Trigger.EnterActions>
                     </Trigger>
                     <Trigger Property="StopAnimation" Value="true">
                         <Trigger.EnterActions>
                             <StopStoryboard BeginStoryboardName="moveStory">
                             </StopStoryboard>
                         </Trigger.EnterActions>
                     </Trigger>
                     <Trigger Property="State" Value="1">
                         <Setter TargetName="rec1" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec2" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec3" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec4" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec5" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec6" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec7" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec8" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec9" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec10" Property="Fill" Value="SeaGreen"/>
                         <Setter TargetName="rec11" Property="Fill" Value="SeaGreen"/>
                     </Trigger>
                 </ControlTemplate.Triggers>
             </ControlTemplate>
         </Setter.Value>
     </Setter>
 </Style>

 

四 效果演示

Xaml代碼如下:

<Window x:Class="WpfApp1.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:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="768" Width="1366">
    <Canvas>
        <local:MechanicalPumpControl x:Name="pump" Canvas.Left="115" Canvas.Top="85"/>
        <Button Content="START" Width="60" Height="30"  Canvas.Left="363" Canvas.Top="94" Click="STARTButton_Click"/>
        <Button Content="STOP"  Width="60" Height="30"  Canvas.Left="363" Canvas.Top="143" Click="STOPButton_Click"/>
    </Canvas>
</Window>

後臺代碼如下:

public partial class MainWindow : Window
{
    public MainWindow()
    {
        InitializeComponent();
    }
    private void STARTButton_Click(object sender, RoutedEventArgs e)
    {
        pump.State = 1;
    }
    private void STOPButton_Click(object sender, RoutedEventArgs e)
    {
        pump.State = 0;
    }
}

 

__ 以 上 __

一團靜火的頭像
  • 本文作者: 一團靜火
  • 本文鏈接: https://www.cnblogs.com/wwwen/p/17070859.html
  • 關於博主: 水平有限,不足或錯誤之處,請批評指正。如果文章對您有幫助,可以點擊文章右下角【推薦】一下。
  • 版權聲明: 本博客所有文章除特別聲明外,系原創文章,均採用 BY-NC-SA 許可協議。轉載請註明出處!並保留此段內容。

  • 您的分享是我們最大的動力!

    -Advertisement-
    Play Games
    更多相關文章
    • 談談你對 Java 平臺的理解?“Java 是解釋執行”,這句話正確嗎? Java 本身是一種面向對象的語言,最顯著的特性有兩個方面,一是所謂的“一處編譯,處處運行”(Write once,run anywhere),能夠非常容易地獲得跨平臺能力;另外就是垃圾收集(GC,Garbage Collec ...
    • 首先我們來嘗試將分片的圖片複原為正常的圖片 這裡是六張切成小細條的圖片,原本是一張大圖的,現在我們用python將他們合併到一塊,題外話圖片來源於中華連環畫,*http://www.zhlhh.com/* 這個網站內有很多優秀的連環畫,而且大部分都是免費,推薦給大家 我的思路是用matlib讀圖片, ...
    • IoC 反轉控制原則也被叫做依賴註入 DI, 容器按照配置註入實例化的對象. 本文將實現一個輕量化的 IoC 容器, 完成對象的實例化和註入, 基於註解不依賴於任何庫. (註解參考 JSR-330) ...
    • 隨著業務的發展,系統會越來越龐大,原本簡單穩定的功能,可能在不斷迭代後複雜度上升,潛在的風險也隨之暴露,導致最終服務不穩定,造成業務價值的損失。而為了減少這種情況,其中一種比較好的方式就是提高代碼質量,比如通過代碼審查,從而降低錯誤風險,但是,代碼審查難度大,代碼缺陷、漏洞不易發現,且審查工作隨著代 ...
    • 作者:京東物流 王北永 姚再毅 1 背景 日常開發過程中,尤其在 DDD 過程中,經常遇到 VO/MODEL/PO 等領域模型的相互轉換。此時我們會一個欄位一個欄位進行 set|get 設置。要麼使用工具類進行暴力的屬性拷貝,在這個暴力屬性拷貝過程中好的工具更能提高程式的運行效率,反之引起性能低下、 ...
    • 對於logback的模板來說,我們是可以自定義的,同時它也提供了一些公開的常量,比如%level,%thread這些,我們如果希望自定義這些常量,需要實現ClassicConverter抽象類,重寫它的convert方法。 系統變數 %thread 當前線程 %d{yyyy-MM-dd HH:mm: ...
    • 一、Lua應用場景 游戲開發 獨立應用腳本 Web 應用腳本 擴展和資料庫插件如:MySQL Proxy 和 MySQL WorkBench 安全系統,如入侵檢測系統 教程採用Aide Lua Pro或AndLua+開發安卓應用。在學習開發安卓應用前,先學習lua的基礎課程。 二、配置手機開發環境 ...
    • 怎麼從菜鳥程式員變成架構師 一、正確理解架構師的工作 架構師一般是不會去探討業務的範疇,他是把整個項目的結構搭出來,並讓程式員去填肉(業務功能部分) ,一般架構師的好壞決定這個項目的工期與質量,現在市面上看見的架構師一般都是別人的框架直接拿來用的,所以就不存在技術提升的範疇。很少會自己搭建框架。如果 ...
    一周排行
      -Advertisement-
      Play Games
    • 最近做項目過程中,使用到了海康相機,官方只提供了C/C++的SDK,沒有搜尋到一個合適的封裝了的C#庫,故自己動手,簡單的封裝了一下,方便大家也方便自己使用和二次開發 ...
    • 前言 MediatR 是 .NET 下的一個實現消息傳遞的庫,輕量級、簡潔高效,用於實現進程內的消息傳遞機制。它基於中介者設計模式,支持請求/響應、命令、查詢、通知和事件等多種消息傳遞模式。通過泛型支持,MediatR 可以智能地調度不同類型的消息,非常適合用於領域事件處理。 在本文中,將通過一個簡 ...
    • 前言 今天給大家推薦一個超實用的開源項目《.NET 7 + Vue 許可權管理系統 小白快速上手》,DncZeus的願景就是做一個.NET 領域小白也能上手的簡易、通用的後臺許可權管理模板系統基礎框架。 不管你是技術小白還是技術大佬或者是不懂前端Vue 的新手,這個項目可以快速上手讓我們從0到1,搭建自 ...
    • 第1章:WPF概述 本章目標 瞭解Windows圖形演化 瞭解WPF高級API 瞭解解析度無關性概念 瞭解WPF體繫結構 瞭解WPF 4.5 WPF概述 ​ 歡迎使用 Windows Presentation Foundation (WPF) 桌面指南,這是一個與解析度無關的 UI 框架,使用基於矢 ...
    • 在日常開發中,並不是所有的功能都是用戶可見的,還在一些背後默默支持的程式,這些程式通常以服務的形式出現,統稱為輔助角色服務。今天以一個簡單的小例子,簡述基於.NET開發輔助角色服務的相關內容,僅供學習分享使用,如有不足之處,還請指正。 ...
    • 第3章:佈局 本章目標 理解佈局的原則 理解佈局的過程 理解佈局的容器 掌握各類佈局容器的運用 理解 WPF 中的佈局 WPF 佈局原則 ​ WPF 視窗只能包含單個元素。為在WPF 視窗中放置多個元素並創建更貼近實用的用戶男面,需要在視窗上放置一個容器,然後在這個容器中添加其他元素。造成這一限制的 ...
    • 前言 在平時項目開發中,定時任務調度是一項重要的功能,廣泛應用於後臺作業、計劃任務和自動化腳本等模塊。 FreeScheduler 是一款輕量級且功能強大的定時任務調度庫,它支持臨時的延時任務和重覆迴圈任務(可持久化),能夠按秒、每天/每周/每月固定時間或自定義間隔執行(CRON 表達式)。 此外 ...
    • 目錄Blazor 組件基礎路由導航參數組件參數路由參數生命周期事件狀態更改組件事件 Blazor 組件 基礎 新建一個項目命名為 MyComponents ,項目模板的交互類型選 Auto ,其它保持預設選項: 客戶端組件 (Auto/WebAssembly): 最終解決方案裡面會有兩個項目:伺服器 ...
    • 先看一下效果吧: isChecked = false 的時候的效果 isChecked = true 的時候的效果 然後我們來實現一下這個效果吧 第一步:創建一個空的wpf項目; 第二步:在項目裡面添加一個checkbox <Grid> <CheckBox HorizontalAlignment=" ...
    • 在編寫上位機軟體時,需要經常處理命令拼接與其他設備進行通信,通常對不同的命令封裝成不同的方法,擴展稍許麻煩。 本次擬以特性方式實現,以兼顧維護性與擴展性。 思想: 一種命令對應一個類,其類中的各個屬性對應各個命令段,通過特性的方式,實現其在這包數據命令中的位置、大端或小端及其轉換為對應的目標類型; ...