自訂控件內控件階層顯示如下圖,UserControl 內有兩個 Panel (TitlePanel 和 ContentPanel),TitlePanel 內再放一個 Label (TitleLabel) 控件,最後透過 Dock 設定讓控件大小可以隨著 UserControl 變化,各子控件 Dock 設定
- TitlePanel:Dock.Top
- ContentPanel:Dock.Fill
- TitleLabel:Dock.Fill
核心功能為使用者在設計階段只能把控件拖曳進 ContentPanel 內、TitlePanel 是無法放控件
該範例整體設計觀念在於 UserControl 無法拖曳控件進入,但是在 UserControlDesigner 內針對子控件去啟用 [設計階段可以拖曳控件進入],以下就用 Code 方式來記錄,部分使用 Code 來達到的效果,會改寫順道驗證看看理解是否正確,筆記重點拆分為
- ContentPanel 和 ContentPanelDesigner
- UCPanel 和 UCPanalDesigner
ContentPanel 和 ContentPanelDesigner
原寫法是使用標準 Panel 並透過 Designer 去移除變更位置、大小相關屬性,讓使用者在設計階段無法進行變更,改寫建立一個 UserControl (ContentPanel 和 ContentPanelDesigner) 並進行相關設定
ContentPanelDesigner 內只進行 SelectionRules 設定,移除 AllSizeable,讓使用者無法用拖曳方式變更 ContentPanel 大小,SelectionRules 請參考該筆記 - [C#] SelectionRules,至於 PostFilterAttributes 和 PostFilterProperties 內的 Code 轉換進 UCContentPanel,以下針對內容作紀錄
- DockingAttribute:移除智能標籤上的 Docking 功能,詳見 [C#] DockingAttribute
- BrowsableAttribute:讓使用者看不見位置、大小相關屬性
using System.Windows.Forms.Design;
namespace UCPanelSample
{
public class UCContentPanelDesigner : ParentControlDesigner
{
public override SelectionRules SelectionRules
{
get
{
SelectionRules selectionRules = base.SelectionRules;
selectionRules &= ~SelectionRules.AllSizeable;
return selectionRules;
}
}
#region 該設定已經移往 UCContentPanel 去
//protected override void PostFilterAttributes(IDictionary attributes)
//{
// base.PostFilterAttributes(attributes);
// attributes[typeof(DockingAttribute)] = new DockingAttribute(DockingBehavior.Never);
//}
//protected override void PostFilterProperties(IDictionary properties)
//{
// base.PostFilterProperties(properties);
// var propertiesToRemove = new string[] {
// "Dock", "Anchor",
// "Size", "Location", "Width", "Height",
// "MinimumSize", "MaximumSize",
// "AutoSize", "AutoSizeMode",
// "Visible", "Enabled",
// };
// foreach (var item in propertiesToRemove)
// {
// if (properties.Contains(item))
// properties[item] = TypeDescriptor.CreateProperty(this.Component.GetType(),
// (PropertyDescriptor)properties[item],
// new BrowsableAttribute(false));
// }
//}
#endregion
}
}
PostFilterAttributes 和 PostFilterProperties 內的 Code 轉換成 UCContentPanel 使用者自訂控件,UCContentPanel 繼承 Panel,有些 Property 可以透過 override 來進行改寫,沒有辦法 override 則是透過 new 來達到 BrowseAttribute(false) 設定,new 使用請參考 [C#] new 關鍵字
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace UCPanelSample
{
[Docking(DockingBehavior.Never)]
[Designer(typeof(UCContentPanelDesigner))]
public class UCContentPanel : Panel
{
[Browsable(false)]
public override DockStyle Dock { get => base.Dock; set => base.Dock = value; }
[Browsable(false)]
public override AnchorStyles Anchor { get => base.Anchor; set => base.Anchor = value; }
[Browsable(false)]
public override Size MinimumSize { get => base.MinimumSize; set => base.MinimumSize = value; }
[Browsable(false)]
public override Size MaximumSize { get => base.MaximumSize; set => base.MaximumSize = value; }
[Browsable(false)]
public override bool AutoSize { get => base.AutoSize; set => base.AutoSize = value; }
[Browsable(false)]
public override AutoSizeMode AutoSizeMode { get => base.AutoSizeMode; set => base.AutoSizeMode = value; }
[Browsable(false)]
public new Size Size { get => base.Size; set => base.Size = value; }
[Browsable(false)]
public new Point Location { get => base.Location; set => base.Location = value; }
[Browsable(false)]
public new int Width { get => base.Width; set => base.Width = value; }
[Browsable(false)]
public new int Height { get => base.Height; set => base.Height = value; }
[Browsable(false)]
public new bool Visible { get => base.Visible; set => base.Visible = value; }
[Browsable(false)]
public new bool Enabled { get => base.Enabled; set => base.Enabled = value; }
}
}
以上即改成 [標準 Panel 搭配 Designer] 為 UserControl (ContentPanel 和 ContentPanelDesigner)
UCPanel 和 UCPanalDesigner
UCPanelDesigner 為自訂控件控件本身,相關設定是禁止控件拖曳進來,重點設定
- EnableDesignMode:雖然控件本身無法接受子控件,但是可以透過 EnableDesignMode 設定,讓子控件可以接受子控件
- CanParent:該控件不允許有子控件
- OnDragOver:禁止拖曳控件
- CreateToolCore:禁止從工具箱拖曳控件
原來從工具箱拖曳控件和從 Form 上拖曳控件,是兩個不同處理方式
using System.ComponentModel;
using System.Drawing.Design;
using System.Windows.Forms;
using System.Windows.Forms.Design;
namespace UCPanelSample
{
public class UCPanelDesigner : ParentControlDesigner
{
public override void Initialize(IComponent component)
{
base.Initialize(component);
var contentsPanel = ((UCPanel)Control).ContentsPanel;
EnableDesignMode(contentsPanel, nameof(UCPanel));
}
public override bool CanParent(Control control)
{
return false;
}
protected override void OnDragOver(DragEventArgs de)
{
de.Effect = DragDropEffects.None;
}
protected override IComponent[] CreateToolCore(ToolboxItem tool, int x, int y, int width, int height, bool hasLocation, bool hasSize)
{
return null;
}
}
}
UCPanel 重點
- ContentsPanel Property 設計:讓 UCPanelDesigner 可以在建構式內抓到它,並開啟 EnableDesignMode,也因此要避免使用者去變化它的位置和大小
- TitleFont Property:自行加上去的 Property,搭配啟用 TitleLabel 和 TitlePanel AutoSize,使其在設計階段可以根據需求調整字型大小
- TypeDescriptor.AddAttributes:原寫法是透過 Code 把 UCContentPanelDesigner 綁定上 UCContentPanel,這部分已經改寫成 UserControl
using System.ComponentModel;
using System.Drawing;
using System.Windows.Forms;
namespace UCPanelSample
{
[Designer(typeof(UCPanelDesigner))]
public partial class UCPanel : UserControl
{
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public UCContentPanel ContentsPanel
{
get { return ContentPanel; }
}
public string TitleText
{
get { return Titlelabel.Text; }
set { Titlelabel.Text = value; }
}
// 自行增加的屬性
public Font TitleFont
{
get { return Titlelabel.Font; }
set { Titlelabel.Font = value; }
}
public UCPanel()
{
InitializeComponent();
// 變更 TitleFont 時,TitlePanel 高度才會一併變化
Titlelabel.AutoSize = true;
TitlePanel.AutoSize = true;
// 直接加進去,就不用另外成立一個 UserControl-ContentPanel
// TypeDescriptor.AddAttributes(ContentsPanel, new DesignerAttribute(typeof(UCContentPanelDesigner)));
}
}
}
變化字型大小效果
沒有留言:
張貼留言