WPF開發快速入門【4】自定義控制項與用戶控制項

来源:https://www.cnblogs.com/seabluescn/archive/2022/08/23/16579297.html
-Advertisement-
Play Games

概述 本文描述WPF的自定義控制項和用戶控制項。 自定義控制項 前面文章介紹了WPF的ControlTemplate,當我們對系統控制項自帶的樣式不太滿意時,我們可以通過控制項模板自定義用戶的樣式,以Button為例,我們可以設計一個圓形的按鈕,並通過觸發器控制一些動態效果。在使用控制項模板時,我們通過Temp ...


概述

本文描述WPF的自定義控制項和用戶控制項。

 

自定義控制項

前面文章介紹了WPF的ControlTemplate,當我們對系統控制項自帶的樣式不太滿意時,我們可以通過控制項模板自定義用戶的樣式,以Button為例,我們可以設計一個圓形的按鈕,並通過觸發器控制一些動態效果。在使用控制項模板時,我們通過TemplateBinding來引用控制項的一些屬性,這個屬性的範圍僅限於Button本身所擁有的屬性。

如果我想設計一款帶圖片的按鈕,通過控制項模板就實現不了了,因為這個圖片按鈕的控制項應該具備一個類似Image這樣的屬性,但Button控制項沒有這個屬性,所以就實現不了我們想要的功能了。

這時候可以使用自定義控制項來解決問題。

我們新建一個ImageButton的自定義控制項,系統自動生成一個類文件和一個樣式文件: 

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

//Generic.xaml
    <Style TargetType="{x:Type local:ImageButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ImageButton}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="{TemplateBinding BorderBrush}"
                            BorderThickness="{TemplateBinding BorderThickness}">
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

 首先我們需要把ImageButton 父類修改為Button,表示這個控制項功能繼承於Button,然後我們為這個類增加一個Image屬性

        public ImageSource Image
        {
            get { return (ImageSource)GetValue(ImageProperty); }
            set { SetValue(ImageProperty, value); }
        }

        public static readonly DependencyProperty ImageProperty =
            DependencyProperty.Register("Image", typeof(ImageSource), typeof(ImageButton), new PropertyMetadata(null));

此時,這個控制項的後臺代碼就完成了。

然後我們再仔細看看Generic.xaml中對於local:ImageButton這個控制項的樣式描述,這不就是修改它的控制項模板嗎?不過此時,除了Button的現有屬性,我們還多了一個Image屬性可以使用。

下麵我們完善一下這個控制項模板的描述。

    <Style TargetType="{x:Type local:ImageButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ImageButton}">
                    <Border Background="{TemplateBinding Background}"
                            BorderBrush="Gray"
                            BorderThickness="1">
                        <StackPanel Orientation="Horizontal">
                            <Image Source="{TemplateBinding Image}"/>
                            <Label Content="{TemplateBinding Content}" VerticalAlignment="Center"/>
                        </StackPanel>
                    </Border>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

 這樣一個自定義控制項就做好了。

 

 和控制項模板一樣,我們還是可以通過Trigger控制控制項的一些動態效果:

    <Style TargetType="{x:Type local:ImageButton}">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="{x:Type local:ImageButton}">
                    <Border x:Name="border">
                        ...
                    </Border>                   
                    <ControlTemplate.Triggers>
                        <Trigger Property="IsMouseOver" Value="True">
                            <Setter TargetName="border" Property="Background" Value="LightBlue" />
                            <Setter TargetName="border" Property="BorderBrush" Value="Gray" />
                            <Setter TargetName="image" Property="Margin" Value="2" />
                        </Trigger>
                        <Trigger Property="IsEnabled" Value="False">
                            <Setter TargetName="border" Property="Background" Value="LightGray" />
                            <Setter TargetName="image" Property="Opacity" Value="0.2" />
                        </Trigger>
                    </ControlTemplate.Triggers>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

  

用戶控制項

用戶控制項比較簡單,就是通過一些現有控制項的組合,形成一個可以通用的控制項。例如:通過組合一個加號的圖片、一個減號的圖片、一個文本框,我們可以組合一個NumericUpDown控制項。 

<UserControl x:Class="LearnWPF.Controls.NumericUpDown">    
    <Border BorderThickness="1" BorderBrush="LightGray" >
        <Grid >
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="30"/>
                <ColumnDefinition Width="50"/>
                <ColumnDefinition Width="30"/>
            </Grid.ColumnDefinitions>
            <Border Grid.Column="0" >
                <Image Source="Images/Subtract.png" Margin="4"
                       MouseDown="ButtonSubtract_Click">
                </Image>
            </Border>
            <TextBox x:Name="txtValue" Text="1.220"                      
                     TextChanged="txtValue_TextChanged"/>
            <Border Grid.Column="2">
                <Image Source="Images/Add.png" Margin="4"
                       MouseDown="ButtonAdd_Click">
                </Image>
            </Border>
        </Grid>
    </Border>
</UserControl>

 我們可以給控制項增加一個Value的屬性,然後當用戶點擊圖片按鈕時,我們修改Value的值即可。

        private void ButtonAdd_Click(object sender, RoutedEventArgs e)
        {
            Value += Increment;           
        }

        private void ButtonSubtract_Click(object sender, RoutedEventArgs e)
        {
            Value -= Increment;            
        }

 此時,這個用戶控制項就開發完成了。但它不支持MVVM模式,因為Value屬性不是依賴屬性,我們需要把Value屬性定義為依賴屬性:

        public decimal Value
        {
            get { return (decimal)GetValue(ValueProperty); }
            set { SetValue(ValueProperty, value); }
        }

        public static readonly DependencyProperty ValueProperty =
               DependencyProperty.Register("Value", typeof(decimal), typeof(NumericUpDown), new UIPropertyMetadata(new decimal(), ValuePropertyChanged));

        private static void ValuePropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs arg)
        {
            NumericUpDown control = obj as NumericUpDown;
            decimal Data = (decimal)arg.NewValue;
            control.txtValue.Text = Math.Round(Data, control.DecimalPlaces).ToString();
        }

 此時Value屬性就支持MVVM,而且支持雙向Binding模式

<xyc:NumericUpDown Value="{Binding Hour,Mode=TwoWay}" Minimum="0" Maximum="23"/>

 由於 Minimum和Maximum不是依賴屬性,只能直接幅值,不能綁定。

 

自繪的用戶控制項

有時候我們需要做一些很奇怪的控制項,如下:

這個也是通過用戶控制項實現。我的經驗是:在用戶控制項里放一個Image控制項,縮放模式設置為Fill,然後在後臺畫個圖並復值給Image控制項即可。

在繪圖時,由於用戶會調整控制項尺寸,所以繪圖控制項的定位是比較麻煩的,我們可以畫一個指定尺寸的圖,然後讓Image來處理縮放,這就比較簡單了。

設計代碼:

<UserControl x:Class="LearnWPF.Controls.Clock"
    <Grid>      
<Image x:Name="imageBitmap" Stretch="Fill" /> </Grid> </UserControl>

 後臺代碼:

    public partial class Clock : UserControl
    {
       
        public Clock()
        {
            InitializeComponent();
            this.Loaded += Clock_Loaded;
        }

        private void Clock_Loaded(object sender, RoutedEventArgs e)
        {
            DrawImage();
        }

        private void DrawImage()
        {
            DrawingGroup group = new DrawingGroup();
            using (DrawingContext ctx = group.Open())
            {
                DrawImageByContext(ctx);
            }
            group.Freeze();
            DrawingImage drawimage = new DrawingImage(group);
            this.imageBitmap.Source = drawimage;
        }

        private void DrawImageByContext(DrawingContext ctx)
        {
            int PicWidth = 500;
            int PicHeight = 500;          
            ctx.DrawRectangle(Brushes.Transparent, null, new Rect(0, 0, PicWidth, PicHeight));
            //拿著ctx盡情繪圖吧           
        }        
    }

   

資源

系列目錄:WPF開發快速入門【0】前言與目錄 

代碼下載:Learn WPF: WPF學習筆記 (gitee.com)


簽名區:
如果您覺得這篇博客對您有幫助或啟發,請點擊右側【推薦】支持,謝謝!

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

-Advertisement-
Play Games
更多相關文章
  • wwm.LeetCodeHelper 倉庫地址:https://gitee.com/wwmin/www.leetcode.helper 1. 說明 wwm.LeetCodeHelper是一款幫助在本地用C#做LeetCode題的一個庫,具有自動拉取題生成csharp文件,自動生成測試用例,自動完成測 ...
  • 我是做11年軟體開發的架構師,想分享跟幹活給到大家。 如果你是剛開始學的大學生,可以看我教學視頻,滿滿的乾貨,幫助你快速找到滿意的工作。也可以通過真實的項目賺點錢。 如果你是剛開始入門的程式員,可以跟我學如何優化代碼,如何搭建框架。快速的學會如何搭建框架。滿足你的財富自由。 源代碼QQ群:43347 ...
  • 快速認識ORM 對象-關係映射,即Object/Relation Mapping,主要實現程式對象到關係資料庫的映射。現在.Net比較流行的ORM框架有:EF、SqlSugar、Dapper、FreeSql、Nhibernate、IBatis.Net等。 O/RM只是一層代碼的封裝,底層還是基於AD ...
  • 常用的定時任務組件有 Quartz.Net 和 Hangfire 兩種,這兩種是使用人數比較多的定時任務組件,個人以前也是使用的 Hangfire ,慢慢的發現自己想要的其實只是一個能夠根據 Cron 表達式來定時執行函數的功能,Quartz.Net 和 Hangfire 雖然都能實現這個目的,但是 ...
  • 1.什麼是PDF/UA文件 PDF/UA,即Universally Accessible PDF,該格式的PDF文件是於2012年8月以ISO標準14289-1發佈的、具有普遍可訪問的PDF文檔標準。為帶標簽的PDF文檔(Tagged PDF Document)和表單的開發人員和作者設定了明確的規則 ...
  • [數據結構1.2-線性表] 動態數組ArrayList(.NET源碼學習) 在C#中,存在常見的九種集合類型:動態數組ArrayList、列表List、排序列表SortedList、哈希表HashTable、棧Stack、隊列Queue、鏈表LinkedList、字典Dictionary、點列陣Bi ...
  • 1.創建Prism Prism是一個用於WPF、Xamarin Form、Uno平臺和 WinUI 中構建鬆散耦合、可維護和可測試的XAML應用程式框架 通過以下方式訪問、使用、學習它: https://github.com/PrismLibrary/Prism https://github.com ...
  • 概述 本文講述下拉框和枚舉類型進行綁定的一些操作。 下拉框的基本操作 設計部分: <ComboBox ItemsSource="{Binding Fruits}" SelectedItem="{Binding SelectedFruit}" SelectedIndex="{Binding Selec ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...