繼承 UserControl 可將現有控制項封裝為可重複使用的複合元件。本文完整示範建立 LabeledTextBox (標籤+文字方塊) 控制項:定義屬性、設計介面、編譯為 DLL、於客戶端專案參考使用。
using System;
using System.Windows.Forms;
namespace MyControls
{
public class LabeledTextBox : UserControl
{
private readonly Label _label = new Label();
private readonly TextBox _textBox = new TextBox();
public LabeledTextBox()
{
// 版面配置
_label.Location = new Point(0, 0);
_label.Size = new Size(100, 20);
_label.AutoSize = false;
_label.TextAlign = ContentAlignment.MiddleRight;
_textBox.Location = new Point(105, 0);
_textBox.Size = new Size(150, 20);
_textBox.Anchor = AnchorStyles.Top | AnchorStyles.Left | AnchorStyles.Right;
Size = new Size(260, 22);
Controls.Add(_label);
Controls.Add(_textBox);
}
// 覆寫 Text 屬性 -> 繫結至 TextBox
public override string Text
{
get => _textBox.Text;
set => _textBox.Text = value;
}
// 新增 LabelText 屬性 -> 繫結至 Label
public string LabelText
{
get => _label.Text;
set => _label.Text = value;
}
// 選擇性:公開內部 TextBox 以支援事件繫結
public TextBox InnerTextBox => _textBox;
}
}
# 命令列編譯 (需參考 System.Windows.Forms.dll)
csc /target:library /r:System.Windows.Forms.dll /r:System.Drawing.dll LabeledTextBox.cs
# 或使用 MSBuild / Visual Studio
# 專案類型:Class Library (.NET Framework / .NET Core / .NET 5+)
# 輸出:MyControls.dll
using System;
using System.Windows.Forms;
using MyControls; // 參考 MyControls.dll
public class DemoForm : Form
{
private readonly LabeledTextBox _name = new LabeledTextBox();
private readonly LabeledTextBox _email = new LabeledTextBox();
private readonly LabeledTextBox _phone = new LabeledTextBox();
private readonly Button _btnShow = new Button();
public DemoForm()
{
_name.LabelText = "姓名:";
_name.Location = new Point(10, 10);
_email.LabelText = "電子郵件:";
_email.Location = new Point(10, 40);
_phone.LabelText = "電話:";
_phone.Location = new Point(10, 70);
_btnShow.Text = "顯示數值";
_btnShow.Location = new Point(10, 100);
_btnShow.Click += (s, e) =>
{
string msg = $"{_name.LabelText}{_name.Text}\n" +
$"{_email.LabelText}{_email.Text}\n" +
$"{_phone.LabelText}{_phone.Text}";
MessageBox.Show(msg, "元件屬性值");
};
Controls.AddRange(new Control[] { _name, _email, _phone, _btnShow });
Text = "自訂元件示範";
ClientSize = new Size(300, 150);
}
[STAThread]
public static void Main()
{
Application.EnableVisualStyles();
Application.SetCompatibleTextRenderingDefault(false);
Application.Run(new DemoForm());
}
}
using System.ComponentModel;
using System.Drawing.Design;
namespace MyControls
{
[ToolboxItem(true)]
[DefaultProperty("LabelText")]
[DefaultEvent("TextChanged")]
public class LabeledTextBox : UserControl
{
// ... 既有程式碼 ...
[Category("自訂屬性")]
[Description("標籤顯示文字")]
[DefaultValue("")]
public string LabelText { get => _label.Text; set => _label.Text = value; }
[Category("自訂屬性")]
[Description("文字方塊內容")]
[Editor(typeof(MultilineStringEditor), typeof(UITypeEditor))]
public override string Text { get => _textBox.Text; set => _textBox.Text = value; }
// 公開 TextBox 事件
[Browsable(true)]
[Category("自訂事件")]
[Description("文字變更時觸發")]
public event EventHandler TextChanged
{
add => _textBox.TextChanged += value;
remove => _textBox.TextChanged -= value;
}
}
}
MyControls 打包為 .nupkg 發佈至私有/公有 NuGet 伺服器,專案透過 Install-Package MyControls 參考。Sign the assembly 避免 DLL Hell。Major.Minor.Patch,破壞性變更升 Major。.Design.dll,避免執行階段載入不必要組件。| 問題 | 原因與解決 |
|---|---|
| 工具箱不顯示元件 | 右鍵工具箱 → 選擇項目 → 瀏覽 DLL;或拖曳 DLL 到工具箱 |
| 設計階段屬性不顯示 | 確認類別為 public、有 public 無參數建構函式、標記 [ToolboxItem(true)] |
| 執行時找不到 DLL | 確認 Copy Local = true 或輸出目錄有 DLL;.NET Core 需 PreserveCompilationContext |
| 錨點/版面跑版 | 設定 Anchor、Dock、AutoSize;複雜版面改用 TableLayoutPanel / FlowLayoutPanel |