# VS自訂有百分比(%)的ProgressBar元件 工作剛好需要用到「顯示百分比(%)的ProgressBar」,但VS原生ProgressBar沒有這個功能。 好險網路上已經有大佬教學,這邊簡單紀錄一下作法,以及可能遇到的問題解法。 >[!Tip] 關鍵步驟 >#### 1. 繼承(Inheritance) : 繼承原控制項 >#### 2. 覆寫(Override) : 覆寫OnPaint事件 >#### 3. 繪製(DrawString) : 繪製文字 ## ✔程式碼 ```csharp= public class ProgressBarWithText : ProgressBar { public ProgressBarWithText() { SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint | ControlStyles.OptimizedDoubleBuffer, true); } protected override void OnPaint(PaintEventArgs e) { Rectangle rect = ClientRectangle; Graphics g = e.Graphics; ProgressBarRenderer.DrawHorizontalBar(g, rect); rect.Inflate(-3, -3); if (Value > 0) { var clip = new Rectangle(rect.X, rect.Y, (int)((float)Value / Maximum * rect.Width), rect.Height); ProgressBarRenderer.DrawHorizontalChunks(g, clip); } string text = string.Format("{0}%", Value * 100 / Maximum); ; using (var font = new Font("Tahoma", 8, FontStyle.Bold)) { SizeF sz = g.MeasureString(text, font); var location = new PointF(rect.Width / 2 - sz.Width / 2, rect.Height / 2 - sz.Height / 2 + 2); g.DrawString(text, font, Brushes.Black, location); } } } ``` ### ✅程式說明 - 第1行,`public class ProgressBarWithText : ProgressBar` - 定義類別,並繼承內建的`ProgressBar`類別,這樣才可沿用原有功能。 - 這裡定義的類別名稱,會在元件製作好後,顯示在工具箱。 - 第3~5行,在`ProgressBarWithText`的建構式,使用`SetStyle()`設定行為權限。 - `SetStyle()`方法,用於設定開發者「修改控制項的繪製和行為」。 - `ControlStyles.UserPaint`,表示會使用此類別定義的繪製事件`OnPaint`,而不是父類別`ProgressBar`的`OnPaint`。 - `ControlStyles.AllPaintingInWmPaint`,減少繪製圖案時的閃爍。 - `ControlStyles.OptimizedDoubleBuffer`,設定DoubleBuffer雙重緩衝。 - 最後的`true`,代表開啟前面提到的行為或權限。 - 第7~24行,覆寫`OnPaint`事件。 - 第22行`DrawString()`是關鍵,用於在元件的`Graphic`上繪製文字。 - `DrawString(字串, 字型, 文字顏色, 繪製位置);` - 專案編譯後,元件就會出現在工具箱。 ![image](https://hackmd.io/_uploads/H11LwV39ke.png)   ![image](https://hackmd.io/_uploads/ByTQFr3ckx.png) ### 📌其它說明 - `ProgressBarWithText`類別要寫在哪? - 因為我只是做一個小工具,所以是直接寫在`MainForm`的`.cs`檔,省時省力。 - 如果是大型專案,或是要製作給其他人使用,通常: - VS有專門撰寫元件的方案,完成後會產生控制項組件,可以在VS裡加入該組件。 - 寫成DLL來引用。 - `SetStyle()`不加`AllPaintingInWmPaint`和`OptimizedDoubleBuffer`會怎樣? - 不知道,大神怎麼寫,我就怎麼~~抄~~寫。 - 因為我拿掉也感覺不出差異,如果有人知道也可以跟我說🥺。 ## 可能遇到的問題 如果跟我一樣直接寫在`MainForm`,某天偶然開啟設計頁面,出現這個錯誤。 `找不到類型'XXXXX.ProgressBarWithText'。請確認已經參考包含此類型的組件。` ![image](https://hackmd.io/_uploads/S1vdoV25yl.png) ❌ **不是製作的元件壞掉了** ⭕ **原因是Visual Studio本身是一個32位元的應用程式。** ![image](https://hackmd.io/_uploads/SkfoHSn9Je.png) - 所以Visual Studio工具箱,也只能讀取使用`x86`編譯產生的元件。 - 如果將`MainForm`切換到`x64`編譯,因為`ProgressBarWithText`剛好寫在`MainForm`,所以也一起被編譯成`x64`了。 - 這樣開啟設計頁面,因為VS讀不到`x64`編譯的元件,所以就跳出錯誤。 (不一定編譯完立刻跳錯,有可能重開專案後才會跳錯) - 但實際上專案還是可以正常編譯,也可以正常顯示/使用元件。 ✅ **解決辦法** 如果是小工具,想偷懶寫在`MainForm`。 - 若沒有位元要求,就直接將專案切換成`AnyCPU`即可。 - 若必須編譯成`x64`,那就在設計頁面時,先切換到`x86`編譯,等要繼續寫程式再切回`x64`環境。 ## 參考資料 [C#下实现在ProgressBar控件上添加百分比](https://blog.csdn.net/zhuimengshizhe87/article/details/20640157) [WinForm重绘进度条ProgressBar显示百分比进度](http://www.windite.com/article/details/j0nobe12) [X64下编译UserControl问题:未能加载工具箱项UserControl,将从工具箱中删除](https://blog.csdn.net/ghhong1988/article/details/106021251)