# 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(字串, 字型, 文字顏色, 繪製位置);`
- 專案編譯後,元件就會出現在工具箱。
   
### 📌其它說明
- `ProgressBarWithText`類別要寫在哪?
- 因為我只是做一個小工具,所以是直接寫在`MainForm`的`.cs`檔,省時省力。
- 如果是大型專案,或是要製作給其他人使用,通常:
- VS有專門撰寫元件的方案,完成後會產生控制項組件,可以在VS裡加入該組件。
- 寫成DLL來引用。
- `SetStyle()`不加`AllPaintingInWmPaint`和`OptimizedDoubleBuffer`會怎樣?
- 不知道,大神怎麼寫,我就怎麼~~抄~~寫。
- 因為我拿掉也感覺不出差異,如果有人知道也可以跟我說🥺。
## 可能遇到的問題
如果跟我一樣直接寫在`MainForm`,某天偶然開啟設計頁面,出現這個錯誤。
`找不到類型'XXXXX.ProgressBarWithText'。請確認已經參考包含此類型的組件。`

❌ **不是製作的元件壞掉了**
⭕ **原因是Visual Studio本身是一個32位元的應用程式。**

- 所以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)