Shawn Burke
微软公司
2001年6月
英文原稿
《Writing Custom Designers for .NET Components》
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dndotnet/html/custdsgnrdotnet.asp
刘志波 译
2001年12月
摘要:这篇文章包括了设计器的各种特性,如何把他们和组件关联起来,如何使用这些特性来创造更强的设计时期用户界面。
内容:
简介
什么是设计器?
组件如何和设计器关联?
修改设计时期的状态信息
定义组件之间的关系
使用组件自己的设计器来更改组件的属性、特性、事件
简化通常要做的工作
与其他组件精确的交互
结论
简介
什么是设计器?
public interface IDesigner : IDisposable { IComponent Component {get;} DesignerVerbCollection Verbs {get;} void DoDefaultAction(); void Initialize(IComponent component); }
组件如何和设计器关联?
namespace MyCompany { [Designer("MyCompany.Design.SysComponentDesigner, MyCompany.Design")] public class SysComponent : Component { } } namespace MyCompany.Design { internal class SysComponentDesigner : ComponentDesigner { // … } }
namespace MyCompany { [Designer(typeof(SysComponentDesigner))] public class SysComponent : Component { internal class SysComponentDesigner : ComponentDesigner{ // … } } }
public DesignerVerbCollection GetComponentVerbs(IComponent comp) { if (comp.Site != null){ IDesignerHost host; host = comp.Site.GetService(typeof(IDesignerHost)); if (host != null){ IDesigner designer; designer = host.GetDesigner(comp); if (designer != null){ return designer.Verbs; } } } return new DesignerVerbCollection(); }
修改设计时期的状态信息
public class DragDropControlDesigner : ControlDesigner { public override void Initialize(IComponent c) { base.Initialize(c); ((Control)c).AllowDrop = false; } }
定义组件之间的关系
[Designer(typeof(MainComp.MainCompDesigner))] public class MainComp : Component { public SubCompCollection SubComponents { get { return subCollection; } } internal class MainCompDesigner : ComponentDesigner { public override ICollection AssociatedComponents{ get{ return ((MainComp)base.Component).SubComponents; } } } } [DesignTimeVisible(false)] [Designer(typeof(SubComp.SubCompDesigner))] public class SubComp : Component { public SubCompCollection SubSubComponents { get { return subCollection; } } internal class SubCompDesigner : ComponentDesigner { public override ICollection AssociatedComponents{ get{ // Only return sited subs in this case. // For example, this component could have // a number of sub components that were // added by the component and aren't sited // on the design surface. We don't want // to move those around. // ArrayList comps = new ArrayList(); foreach (SubComp sc in ((SubComp)Component).SubSubComponents) { if (sc.Site != null) { comps.Add(sc); } } return comps; } } } }
使用组件自己的设计器来更改组件的属性、特性、事件
public class SimpleControlDesigner : ComponentDesigner { bool locked; public bool Enabled { get { return (bool)ShadowProperties["Enabled"]; } set { // note this value is not passed to the actual // control this.ShadowProperties["Enabled"] = value; } } private bool Locked { get { return locked; } set { locked = value; } } public bool Visible { get { return (bool)ShadowProperties["Visible"]; } set { // note this value is not passed to the actual // control this.ShadowProperties["Visible"] = value; } } public void Initialize(IComponent c) { base.Initialize(c); Control control = c as Control; if (control == null) { throw new ArgumentException(); } // pick up the current state and push it // into our shadow props to initialize them. // this.Visible = control.Visible; this.Enabled = control.Enabled; control.Visible = true; control.Enabled = true; } protected override void PreFilterProperties(IDictionary properties) { base.PreFilterProperties(properties); // replace Visible and Enabled with our shadowed versions. // properties["Visible"] = TypeDescriptor.CreateProperty( typeof(SimpleControlDesigner), (PropertyDescriptor)properties["Visible"], new Attribute[0]); properties["Enabled"] = TypeDescriptor.CreateProperty( typeof(SimpleControlDesigner), (PropertyDescriptor)properties["Enabled"], new Attribute[0]); // and add the Locked property // properties["Locked"] = TypeDescriptor.CreateProperty( typeof(SimpleControlDesigner), "Locked", typeof(bool), CategoryAttribute.Design, DesignOnlyAttribute.Yes); } }
简化通常要做的工作
[Designer(typeof(ColorButton.ColorButtonDesigner))] public class ColorButton : System.Windows.Forms.Button { internal class ColorButtonDesigner : ControlDesigner { private DesignerVerbCollection verbs = null; private void OnVerbRed(object sender, EventArgs e) { Control.BackColor = Color.Red; } private void OnVerbGreen(object sender, EventArgs e){ Control.BackColor = Color.Green; } private void OnVerbBlue(object sender, EventArgs e) { Control.BackColor = Color.Blue; } public override DesignerVerbCollection Verbs { get { if (verbs == null) { verbs = new DesignerVerbCollection(); verbs.Add( new DesignerVerb( "Red", new EventHandler(OnVerbRed))); verbs.Add( new DesignerVerb( "Blue", new EventHandler(OnVerbBlue))); verbs.Add( new DesignerVerb( "Green", new EventHandler(OnVerbGreen))); } return verbs; } } } }
与其他组件精确的交互
private void OnVerbGreen(object sender, EventArgs e){ PropertyDescriptor backColorProp = TypeDescriptor.GetProperties(Control)["BackColor"]; if (backColorProp != null) { backColorProp.SetValue(Control, Color.Green); } }
internal class RadioButtonDesigner : ControlDesigner { public bool Checked { get { // pass the get down to the control. // return ((RadioButton)Control).Checked; } set { // set the value into the control // ((RadioButton)Control).Checked = value; // if the value for this radio button // was set to true, notify that others have changed. // if (value) { IComponentChangeService ccs = (IComponentChangeService) GetService(typeof(IComponentChangeService)); if (ccs != null) { PropertyDesciptor checkedProp = TypeDescriptor.GetProperties(typeof(RadioButton))["Checked"]; foreach(RadioButton rb in Control.Parent.Controls) { if (rb == Control || !(rb is RadioButton)) continue; ccs.OnComponentChanging(rb, checkedProp); ccs.OnComponentChanged(rb,chedkedProp, null, null); } } } } } protected override void PreFilterProperties( IDictionary properties) { base.PreFilterProperties(properties); // shadow the checked property so we can intercept the set. // properties["Checked"] = TypeDescriptor.CreateProperty( typeof(RadioButtonDesigner), (PropertyDescriptor)properties["Checked"], new Attribute[0]); } }
结论
设计器可以给任何实现IComponent的对象编写并且驻扎(sited)在设计界面上。这对Windows Forms Controls、Web Form Controls和其他的组件来说都是适用的。给组件订制的设计器可以有不同于标准的设计界面而且可以让设计时期代码和执行时期代码分离,减少发布文件大小而且可以更强的控制组件的设计期行为。
从扩展性能上说,从.NET框架的设计时期接口和类导出的对象有能力订制自己的设计期行为,而以前的框架没有这些。运用这些能力来扩展组件就可以有更加丰富的设计期行为和运行期对象模型。
从扩展性能上说,从.NET框架的设计时期接口和类导出的对象有能力订制自己的设计期行为,而以前的框架没有这些。运用这些能力来扩展组件就可以有更加丰富的设计期行为和运行期对象模型。