WinForm Custom(一) Button控制項

来源:https://www.cnblogs.com/zhuanghamiao/archive/2022/06/07/winform-custom-button.html
-Advertisement-
Play Games

以下代碼實現自定義Button,繼承WinForm的Button,新增了邊框、圓角設置的相關屬性。 public class ZhmButton : Button { private int borderSize = 0; // 邊框 private Color borderColor = Colo ...



以下代碼實現自定義Button,繼承WinForm的Button,新增了邊框、圓角設置的相關屬性。

    public class ZhmButton : Button
    {
        private int borderSize = 0; // 邊框
        private Color borderColor = ColorTranslator.FromHtml("#5A6268"); // 邊框色
        private int borderRadius = 25; //圓角角度

        public ZhmButton()
        {
            // 去除系統預設樣式,並設置自定義樣式
            this.FlatStyle = FlatStyle.Flat;
            this.FlatAppearance.BorderSize = 0;

            this.Size = new Size(150, 46);
            this.BackColor = ColorTranslator.FromHtml("#23272B");
            this.ForeColor = Color.White;
            this.Resize += ZhmButton_Resize;
        }

        [Category("擴展屬性")]
        public int BorderSize { get => borderSize; set { borderSize = value; this.Invalidate(); } }
        [Category("擴展屬性")]
        public Color BorderColor { get => borderColor; set { borderColor = value; this.Invalidate(); } }
        [Category("擴展屬性")]
        public int BorderRadius
        {
            get => borderRadius; set
            {
                borderRadius = value <= Height ? value : Height;
                this.Invalidate();
            }
        }


        private GraphicsPath DrawGraphicsPath(RectangleF rectangle, float radius)
        {
            GraphicsPath path = new GraphicsPath();
            path.StartFigure();

            // 從左上角開始按順時針方向 分別在空間的四個角追加一段圓弧
            //       270°
            //        |
            //180°----|-----0°
            //        |
            //       90°
            path.AddArc(rectangle.X, rectangle.Y, radius, radius, 180, 90);
            path.AddArc(rectangle.Width - radius, rectangle.Y, radius, radius, 270, 90);
            path.AddArc(rectangle.Width - radius, rectangle.Height - radius, radius, radius, 0, 90);
            path.AddArc(rectangle.X, rectangle.Height - radius, radius, radius, 90, 90);

            path.CloseFigure();
            return path;
        }

        private void ZhmButton_Resize(object sender, EventArgs e)
        {
            if (borderRadius > this.Height)
                borderRadius = this.Height;
        }

        protected override void OnPaint(PaintEventArgs pevent)
        {
            base.OnPaint(pevent);

            pevent.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
            RectangleF rectSurface = new RectangleF(0, 0, this.Width, this.Height);
            RectangleF rectBorder = new RectangleF(1, 1, this.Width - 0.8F, this.Height - 1);
            if (BorderRadius > 2)
            {
                using (var pathSurface = DrawGraphicsPath(rectSurface, BorderRadius))
                using (var pathBorder = DrawGraphicsPath(rectBorder, BorderRadius - 1))
                using (var penSurface = new Pen(this.Parent.BackColor, 2))
                using (var penBorder = new Pen(BorderColor, BorderSize))
                {
                    penBorder.Alignment = PenAlignment.Inset;
                    this.Region = new Region(pathSurface);
                    pevent.Graphics.DrawPath(penSurface, pathSurface);
                    if (BorderSize > 0)
                        pevent.Graphics.DrawPath(penBorder, pathBorder);
                }
            }
            else
            {
                this.Region = new Region(rectSurface);
                if (BorderSize > 0)
                {
                    using (var penBorder = new Pen(BorderColor, BorderSize))
                    {
                        penBorder.Alignment = PenAlignment.Inset;
                        pevent.Graphics.DrawRectangle(penBorder, 0, 0, this.Width - 1, this.Height - 1);
                    }
                }
            }
        }

        protected override void OnHandleCreated(EventArgs e)
        {
            base.OnHandleCreated(e);
            this.Parent.BackColorChanged += Parent_BackColorChanged;
        }

        private void Parent_BackColorChanged(object sender, EventArgs e)
        {
            if(this.DesignMode)
                this.Invalidate();
        }
    }

--------------------------------------------------------以下僅為湊字數---------------------------------------------------------------------------------
使用 .NET Framework 可以開發和實現新的控制項。 可以通過繼承來擴展熟悉的用戶控制項和現有控制項的功能。 還可以編寫自定義控制項,這些控制項執行自己的繪製。
基控制項類
Control 類是 Windows 窗體控制項的基類。 它提供了在 Windows 窗體應用程式中進行可視顯示所需的基礎結構。
Control 類執行下列任務,以便在 Windows 窗體應用程式中提供可視顯示:
公開視窗句柄。
管理消息路由。
提供滑鼠和鍵盤事件,以及許多其他用戶界面事件。
提供高級佈局功能。
包含特定於可視化顯示的多個屬性,如 ForeColor、BackColor、Height 和 Width。
為 Windows 窗體控制項充當 Microsoft® ActiveX® 控制項提供必需的安全性和線程支持。
由於基類提供了大量基礎結構,因此使開發自己的 Windows 窗體控制項變得相對簡單。

控制項種類
Windows 窗體支持三種用戶定義的控制項:複合、擴展和自定義。 以下各節分別介紹各種控制項,並就如何選擇項目中使用的控制項種類提供建議。

複合控制項
複合控制項是封裝在公共容器內的 Windows 窗體控制項的集合。 這種控制項有時稱為用戶控制項。 其包含的控制項稱為構成控制項。
複合控制項包含與每個包含的 Windows 窗體控制項相關聯的所有固有功能,允許選擇性地公開和綁定它們的屬性。 複合控制項還提供了大量的預設鍵盤處理功能,用戶不需要進行任何額外的開發。
例如,可以生成複合控制項,以顯示來自資料庫的客戶地址數據。 此控制項可包括用於顯示資料庫欄位的 DataGridView 控制項、用於處理到數據源的綁定的 BindingSource,以及用於在記錄之間移動的 BindingNavigator 控制項。 可以選擇性地公開數據綁定屬性,還可以將整個控制項打包併在不同應用程式之間重覆使用。 有關這種複合控制項的示例,請參閱如何:應用 Windows 窗體控制項中的特性。
若要創作複合控制項,請從 UserControl 類派生。 基類 UserControl 為子控制項提供了鍵盤路由,並使子控制項可以作為組進行工作。 有關詳細信息,請參閱開發複合 Windows 窗體控制項。

建議
如果為以下情況,則從 UserControl 類繼承:
你想要將多個 Windows 窗體控制項的功能組合到單個可重用單元。
擴展控制項
你可以從任何現有的 Windows 窗體控制項派生繼承的控制項。 使用此方法,你可以保留 Windows 窗體控制項的所有固有功能,然後通過添加自定義屬性、方法或其他功能來擴展該功能。 可以使用此選項重寫基控制項的繪製邏輯,然後通過更改該控制項的外觀來擴展其用戶界面。
例如,可以創建一個由 Button 控制項派生的控制項,並用它來跟蹤用戶的單擊次數。
在某些控制項中,也可以通過重寫基類的 OnPaint 方法為控制項的圖形用戶界面添加自定義外觀。 對於跟蹤單擊次數的擴展按鈕,可以重寫 OnPaint 方法以調用 OnPaint 的基實現,然後在 Button 控制項的工作區的一角繪製單擊計數。

建議
如果為以下情況,則從 Windows 窗體控制項繼承:
大部分所需功能與現有的 Windows 窗體控制項相同。
不需要自定義圖形用戶界面,或者想為現有控制項設計一個新的圖形用戶界面。

自定義控制項
創建控制項的另一種方法是通過從 Control 繼承,從頭開始充分創建一個控制項。 Control 類提供控制項所需的所有基本功能(包括滑鼠和鍵盤處理事件),但不提供特定於控制項的功能或圖形界面。
相比從 UserControl 或現有 Windows 窗體控制項繼承來說,通過從 Control 類繼承來創建控制項需要花費更多心思和精力。 由於用戶還需執行大量的實現,因此,控制項可以具有比複合控制項或擴展控制項更好的靈活性,而且可以使控制項完全滿足自己的需要。
若要實現自定義控制項,必須編寫該控制項的 OnPaint 事件的代碼,以及所需的任何功能特定的代碼。 還可以重寫 WndProc 方法並直接處理視窗消息。 這是創建控制項的最強大的方法,但若要有效地使用此技術,需熟悉 Microsoft Win32® API。
時鐘控制項即是一個自定義控制項,它複製模擬時鐘的外觀和行為。 調用自定義繪製來使指針移動,以響應來自內部 Timer 組件的 Tick 事件。 有關詳細信息,請參閱如何:開發簡單的 Windows 窗體控制項。

建議
如果為以下情況,則從 Control 類繼承:
你想要提供控制項的自定義圖形表示形式。
你需要實現不能通過標準控制項實現的自定義功能。

ActiveX 控制項
儘管 Windows 窗體基礎結構已為承載 Windows 窗體控制項進行了優化,但仍可以使用 ActiveX 控制項。 Visual Studio 中對此任務提供支持。 有關詳細信息,請參閱如何:向 Windows 窗體添加 ActiveX 控制項。

無視窗控制項
Microsoft Visual Basic® 6.0 和 ActiveX 技術支持無視窗控制項。 Windows 窗體中不支持無視窗控制項。


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

-Advertisement-
Play Games
更多相關文章
  • 雙親委派機制:當某個類載入器準備載入一個.class位元組碼文件時,它首先將這個載入任務委派給上一級類載入器,上一級載入器再委派到更上一級類載入器,遞歸這個操作直到最頂級的類載入器。 一、類載入器的類別 在介紹Java的雙親委派機制的時候,不得不提ClassLoader(類載入器) 我們編譯的Java ...
  • 一、分散式鏈路追蹤發展簡介 1.1 分散式鏈路追蹤介紹 關於分散式鏈路追蹤的介紹,可以查看我前面的文章 微服務架構學習與思考(09):分散式鏈路追蹤系統-dapper論文學習(https://www.cnblogs.com/jiujuan/p/16097314.html) 。 這裡的 OpenTel ...
  • 條碼的應用已深入生活和工作的方方面面。在處理條碼時,常需要和各種文檔格式相結合。當需要在文檔中插入、編輯或者刪除條碼時,可藉助於一些專業的類庫工具來實現。本文,以操作PDF文件為例,介紹如何在編輯表格時,向單元格中添加條形碼。 【程式環境】 本次功能測試中,使用 Free Spire.PDF for ...
  • 1 Sentinel主頁 https://github.com/alibaba/Sentinel/wiki/%E4%B8%BB%E9%A1%B5 1.1 Sentinel介紹 隨著微服務的流行,服務和服務之間的穩定性變得越來越重要。Sentinel 是面向分散式服務架構的流量控制組件,主要以流量為切 ...
  • 前言 dubbo是一款微服務開發框架,它提供了 RPC通信 與 微服務治理 兩大關鍵能力。作為spring cloud alibaba體系中重要的一部分,隨著spring cloud alibaba在國內活躍起來,dubbo也越來越深受各大公司的青睞。本文就來對dubbo的spi機制源碼進行剖析,看 ...
  • ​ 問題描述 我在Eclipse上運行項目的時候,在我用fileUpload上傳圖片,等到下一次Tomcat刷新的時候,這個照片就沒了,而且點擊查看那個文件夾也查看不到有圖片文件。 原因 我後來在網上查詢相關資料發現是Eclipse整 合Tomcat的問題,因為他們整合之後,你用相對路徑上傳的圖片會 ...
  • 用戶 在系統里,用戶是一個核心概念。它代表了一個人的唯一身份標識,除了與角色、團隊、組織架構等有關,甚至還會影響到在同一個界面不同的用戶操作流程與顯示內容都會發生變化,再複雜一點的話,或許在同一個系統內的一個用戶進入到不同產品後的身份也會變化 用戶與角色 用戶可以擁有一個或多個角色,讓角色作為許可權組 ...
  • 當服務端啟動後,但是telnet其監聽的埠卻失敗了。或者當服務端運行了一段時間後,突然其監聽的埠telnet不通了。當類似這樣情況出現時,要如何排查問題所在了? ...
一周排行
    -Advertisement-
    Play Games
  • C#TMS系統代碼-基礎頁面BaseCity學習 本人純新手,剛進公司跟領導報道,我說我是java全棧,他問我會不會C#,我說大學學過,他說這個TMS系統就給你來管了。外包已經把代碼給我了,這幾天先把增刪改查的代碼背一下,說不定後面就要趕鴨子上架了 Service頁面 //using => impo ...
  • 委托與事件 委托 委托的定義 委托是C#中的一種類型,用於存儲對方法的引用。它允許將方法作為參數傳遞給其他方法,實現回調、事件處理和動態調用等功能。通俗來講,就是委托包含方法的記憶體地址,方法匹配與委托相同的簽名,因此通過使用正確的參數類型來調用方法。 委托的特性 引用方法:委托允許存儲對方法的引用, ...
  • 前言 這幾天閑來沒事看看ABP vNext的文檔和源碼,關於關於依賴註入(屬性註入)這塊兒產生了興趣。 我們都知道。Volo.ABP 依賴註入容器使用了第三方組件Autofac實現的。有三種註入方式,構造函數註入和方法註入和屬性註入。 ABP的屬性註入原則參考如下: 這時候我就開始疑惑了,因為我知道 ...
  • C#TMS系統代碼-業務頁面ShippingNotice學習 學一個業務頁面,ok,領導開完會就被裁掉了,很突然啊,他收拾東西的時候我還以為他要旅游提前請假了,還在尋思為什麼回家連自己買的幾箱飲料都要叫跑腿帶走,怕被偷嗎?還好我在他開會之前拿了兩瓶芬達 感覺感覺前面的BaseCity差不太多,這邊的 ...
  • 概述:在C#中,通過`Expression`類、`AndAlso`和`OrElse`方法可組合兩個`Expression<Func<T, bool>>`,實現多條件動態查詢。通過創建表達式樹,可輕鬆構建複雜的查詢條件。 在C#中,可以使用AndAlso和OrElse方法組合兩個Expression< ...
  • 閑來無聊在我的Biwen.QuickApi中實現一下極簡的事件匯流排,其實代碼還是蠻簡單的,對於初學者可能有些幫助 就貼出來,有什麼不足的地方也歡迎板磚交流~ 首先定義一個事件約定的空介面 public interface IEvent{} 然後定義事件訂閱者介面 public interface I ...
  • 1. 案例 成某三甲醫預約系統, 該項目在2024年初進行上線測試,在正常運行了兩天後,業務系統報錯:The connection pool has been exhausted, either raise MaxPoolSize (currently 800) or Timeout (curren ...
  • 背景 我們有些工具在 Web 版中已經有了很好的實踐,而在 WPF 中重新開發也是一種費時費力的操作,那麼直接集成則是最省事省力的方法了。 思路解釋 為什麼要使用 WPF?莫問為什麼,老 C# 開發的堅持,另外因為 Windows 上已經裝了 Webview2/edge 整體打包比 electron ...
  • EDP是一套集組織架構,許可權框架【功能許可權,操作許可權,數據訪問許可權,WebApi許可權】,自動化日誌,動態Interface,WebApi管理等基礎功能於一體的,基於.net的企業應用開發框架。通過友好的編碼方式實現數據行、列許可權的管控。 ...
  • .Net8.0 Blazor Hybird 桌面端 (WPF/Winform) 實測可以完整運行在 win7sp1/win10/win11. 如果用其他工具打包,還可以運行在mac/linux下, 傳送門BlazorHybrid 發佈為無依賴包方式 安裝 WebView2Runtime 1.57 M ...