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
    • @ 先看一下導出的整體效果(如下圖),其中標註的區域都是通過後臺動態生成的: 一、先在Word中建立好表格模板 1.1、參數創建方法(Word和WPS) 1.1.1、Office中Word域的創建 1.1.1.1、選中指定的單元格 -> 點擊頭部工具欄中的”插入“ -> 選擇 ”文檔部件“ -> 選 ...
    • 在實際工作中,經常會有一些需要定時操作的業務,如:定時發郵件,定時統計信息等內容,那麼如何實現才能使得我們的項目整齊劃一呢?本文通過一些簡單的小例子,簡述在.Net6+Quartz實現定時任務的一些基本操作,及相關知識介紹,僅供學習分享使用,如有不足之處,還請指正。 ...
    • 紙殼CMS支持將評論、留言、表單提交、訂閱等通知,通過WebHook發送到第三方平臺,比如釘釘。 創建釘釘WebHook 需要在釘釘群中創建自定義機器人,具體方法可以參考釘釘的官方文檔: 自定義機器人接入 需要註意的是,在安全設置中不要使用加簽,使用自定義關鍵字即可。在發送的消息中,只要包含這個關鍵 ...
    • 向下轉型的使用 Java的多態性: 父類指向子類的聲明 Animal animal = new Dog()//Dog()重寫了父類Animal 有了對象的多態性以後,記憶體實際上載入的是==子類==的屬性和方法,但是由於變數聲明為==父類類型==,導致編譯時只能調用父類的屬性和方法,子類特有的屬性方法 ...
    • spring源碼環境搭建 組件 版本 jdk 1.8.0_192 spring-framework 5.3.x gradle 7.5.1 idea 2022.3.3 aspectJ 1.9 可根據spring-framwork項目說明靈活選擇 一、拉取spring-framework項目 1、spr ...
    • 首先任何的商業邏輯,光流量增長,沒法變現是沒用的。 就像博客群發提效工具,得有對應的用戶,更得有對應付費用戶群體的畫像。剩下的就是靠增長,被動讓他們找到你的產品,用產品解決他們痛點,他們自然而然會付費。 下麵大致分享下從三個方向分享下: 用戶痛點 -> 真正的付費用戶群體 產品價值 PLG 增長 一 ...
    • Object類的使用 Object類 Object類中的方法可以在網上搜索得到 Object類是所有java類的父類 如果類在聲明中未使用extends關鍵字指明其父類,則預設父類為java.lang.Object類 Object類中的功能(屬性、方法)具有通用性。 屬性:無 方法:equals() ...
    • Qt 源碼分析之moveToThread 這一次,我們來看Qt中關於將一個QObject對象移動至一個線程的函數moveToThread Qt使用線程的基本方法 首先,我們簡單的介紹一下在Qt中使用多線程的幾種方法: 重寫QThread的run函數,將要在多線程執行的任務放到run函數里 /*myt ...
    • 包裝類的使用 包裝類的使用 java提供8種基本數據類型對應的包裝類,使得基本數據類型變數具有類的特征 掌握:==基本數據類型、包裝類、String==三者之間的互相轉換 自動裝箱與自動拆箱==[基本數據類型和包裝類的轉換]== JDK5.0新特性,自動裝箱與自動拆箱。 class Test{ pu ...
    • 本文已經收錄到Github倉庫,該倉庫包含電腦基礎、Java基礎、多線程、JVM、資料庫、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分散式、微服務、設計模式、架構、校招社招分享等核心知識點,歡迎star~ Github地址 大家好,我是大彬~ 今天來聊聊接 ...