编写组件自己的设计器

http://ms.mblogger.cn/soil/posts/5046.aspx

当设计器改变了一个组件的状态时,其他的一些组件可能会对这个改变有兴趣。举一个例子,如果你改变了一个组件的背景为红色,属性窗口会显示这个改变信息。一般的,组件状态的改变会通过IComponentChangeService广播出去。VS.NET设计器中的其他服务会监听这个IComponentChangeService,包括代码持久性引擎,redo/undo工具,属性窗口和对这个更新有兴趣的属性的更新状态。

IComponentService在一个组件将要改变和改变后都会得到注意。任何客户都会收到两个主要的通知信息:OnComponentChanging和OnComponentChanged。OnComponentChanging必须在OnComponentChanged之前触发,而OnComponentChanged并不需要在IComponentChanging之后调用。当由于某种原因取消动作时这个就可以起作用。IComponentChangeService有好几个监听通知的事件。
lComponentChanging
lComponentChanged
lComponentAdding
lComponentAdded
lComponentRemoving
lComponentRemoved
lComponentRename
服务仅仅允许ComponentChanging和ComponentChanged手动触发。其他的事件都是设计器在组件添加、删除、更改名字的时候自动触发的。
当通过PropertyDescriptor改变一个属性的值时,组件通知信息自动就发送出去,也就是这是一个相当简便的方式来做一些通知工作。
在上面的例子里,如果我们用PropertyDescriptor来通知改变(属性窗口会自动更新),我们把动作处理的代码改成如下:

private void OnVerbGreen(object sender, EventArgs e){
PropertyDescriptor backColorProp =
TypeDescriptor.GetProperties(Control)["BackColor"];

if (backColorProp != null) {
backColorProp.SetValue(Control, Color.Green);
}
}

同样有一些情况是改变一个属性的值会影响到其他的一些属性,或者是一些情况是许多属性的改变同时发生。考虑到性能因素,直接修改对象的属性值(而不是使用PropertyDescriptor),然后接着调用通知。用PropertyDescriptor来访问属性会比直接来得慢。
我们看一下RadioButton。当改变一个RadioButton的值为true时,其他的有同一个parent对象的RadioButton就应该设置为false。运行期代码会自动处理这些,不过设计时期还是要自己来处理比较好。在这个例子里,我们把Checked属性影化来中途截取改变的值。当值设为true时,我们就循环处理RadioButton的兄弟,并且通知每一个RadioButton的IComponentService来改变他们的值。我们通过调用ComponentDesigner的GetService方法来得到一个IComponentService对象句柄然后调用他的实例。

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框架的设计时期接口和类导出的对象有能力订制自己的设计期行为,而以前的框架没有这些。运用这些能力来扩展组件就可以有更加丰富的设计期行为和运行期对象模型。
原文地址:https://www.cnblogs.com/chulia20002001/p/1837213.html