ASP.net控件开发系列(四)
在上篇文章中,和大家探讨了属性和aspx文件中的HTML style 标签和文本的关系,遗漏了两点:
1、EnCodedInnerDefaultProperty和InnerDefaultProperty在使用中的区别,可能有些朋友对这个不是很清楚,
EncodedInnerDefaultProperty属性是不允许内含控件对象的,比方说,声明了EncodedInnerDefaultProperty的DataList的Text属性是
不允许你设为“<table ......>.....</table>”之类的含HTML标签(准确的说是可解悉为对象)的内容的。而声明为
InnerDefaultProperty的DropDownList的Items属性你可以写<asp:datalist value = "1">1</asp:datalist>这样的内容。
2、一个属性如果根本不应该在aspx文件中控制,怎么办呢?
这些我们可以这个Attribute:
DesignerSerilizationVisibility(DesignerSerializationVisibility.Hidden)
好,我们转入今天的正题:属性与属性窗格
相信大部分的程序员在大部分情况下是使用属性窗格来设置控件对象的属性的,所以,属性窗格也是控件设计中至关重要的。
在说属性窗格时,我们先要来了解一下PropertyGrid,PropertyGrid是一个位于System.Windows.Forms.dll下的控件,VS.net等IDE
工具就是用它来提供属性显示、操作功能,大家可能平时并没有这个控件的概念,虽然也许你每天都在使用它提供的功能。
如果你想更进一步认识它,可以建一个Winform工程,将该控件添加到VS.net工具箱中,再拉一个到窗体中了解一下它,这个工具我们一般情况下编程是用不到它的,不过当你要为控件提供定制的设计器(如DataGrid的属性编辑器)时,使用它是个不错的
主意(关于各种设计器及PropertyGrid的更多东西,我会在以后的控件设计设计时功能篇再述说)。
PropertyGrid在显示控件的属性时有多种不同的形式,
比如说:Button的Font属性,ProperyGrid把它显示为一个可展开、折叠的属性组,首先Font属性的类型是一个复杂的类
(FontInfo),它有很多的子属性,然后,你要应用我们在上面提到的Attribute:
DesignerSerializationVisibility(DesignerSerializationVisibility.Content)
它表示代码生成器将序列化属性的子属性而不是它本身,怎么理解呢?就是说Button控件的Font属性中的Bold和Underline子属性
将被序列化为(Font-Underline="True" Font-Bold="True"),而不是像Style属性一样乱糟糟序列化为(style="Z-INDEX: 101;
LEFT: 224px; POSITION: absolute; TOP: 240px"),而且在通常情况下,我们会给以上这种属性设上另一个Attribute及其值:
[NotifyParentProperty(true)](System.ComponentModel.NotifyParentPropertyAttribute,默认值为false)它的作用是通知
PropertyGrid从子属性往父级通知一个更改。
DesignerSerializationVisibility的默认值是DesignerSerializationVisibility.Visible;而上面提到的Hidden值会使对应的属性不被序列
化,比如说你做一个SQLServerConnection控件,你会不想提供给用户序列化ConnectPassword属性,将之写在.aspx文件中的功
能。同时,设为Hidden的属性也不会出现在PropertyGrid中
那么如果我只是想一个属性不显示在PropertyGrid中,而可以在.aspx文件中序列化和设值,那么你可以不使用上述Attribute而使
用[Browsable(false)],该Attribute默认值为true,全名是System.ComponentModel.BrowsableAttribute。
接着呢,程序员一般做事是比较有条理的,就像我:),那么我们会想把控件的各种属性分门别类的安置在PropertyGrid中,要
做到这一点,很容易,你只要在属性声明上方注上以下Attribute:
[Category("Behavior")](System.ComponentModel.CategoryAttibute,它的默认值是"Default"),这句话的意思是说把这个属性归为行为
这一部分,请注意,像数据、外观、行为、杂项(Default)等类别,你不必写[Category("行为")]而写成[Category("Behavior")],
VS.net会自动做本地化工作。
接着,你可能想为属性写上几句Comment,你可以使用这个Attribute:
[Description("今天你写控件了吗")](System.ComponentModel.DescriptionAttribute,这个属性可能你也想做到本地化,让注释见
人说人话,见鬼说鬼话,这也是可以的,不过不像Category那么自动,要做的事多点,关于控件的本地化,我们以后再讨论)
现在,我们来看看PropertyGrid对编辑属性提供的几种不同样式的支持:
文本框式、下拉列表式、弹出窗口式。
文本框式是默认的,比如Button的Text;
下拉列表式,比如我写的RockUControl控件的RockToControl属性,以及Validator系列控件的选验证对象的属性;
弹出窗口式,比如颜色属性,提供一个窗体给我们选择。
第一种是默认的,我们不用管,我们来看下拉式的,要实现这种效果,要用到一个好像蜂马牛不相及一样的Attribute:
[TypeConverter(typeof(YourCustomConverter))]
如我的RockUControl控件的RockToControl属性
[Bindable(false)]
[Category("Behavior")]
[DefaultValue("")]
[TypeConverter(typeof(THINControls.WebControls.Designer.FormControlsConverter))]
[Description("要滚动的对象。")]
public string RockToControl
{
get
{
object o = ViewState["RockToControl"];
return (o==null)?"":o.ToString();
}
set
{
ViewState["RockToControl"] = value;
}
}
再看FormControlsConverter类(请认真查看我加的注释)
public class FormControlsConverter:StringConverter
{
public FormControlsConverter()
{
}
//这一个override说明要用下拉列表编辑属性
public override bool GetStandardValuesSupported(ITypeDescriptorContext context)
{
return true;
}
//这个override返回下拉列表项,有朋友曾问怎么实现拿出当前页面的控件,以下就是我摸索出来的代码。
public override System.ComponentModel.TypeConverter.StandardValuesCollection GetStandardValues(ITypeDescriptorContext context)
{
ControlCollection Controls = ((Page)context.Container.Components[0]).Controls;
ArrayList controlsArray = new ArrayList();
for(int i = 0 ;i < Controls.Count ; i++)
{
if((Controls[i] is HtmlTable
|| Controls[i] is HtmlForm
|| Controls[i] is HtmlGenericControl
|| Controls[i] is HtmlImage
|| Controls[i] is Label
|| Controls[i] is DataGrid
|| Controls[i] is DataList
|| Controls[i] is Table
|| Controls[i] is Repeater
|| Controls[i] is Image
|| Controls[i] is Panel
|| Controls[i] is PlaceHolder
|| Controls[i] is Calendar
|| Controls[i] is AdRotator
|| Controls[i] is Xml
))
{
controlsArray.Add(Controls[i].ClientID);
}
}
return new StandardValuesCollection(controlsArray);
}
//return ture的话只能选,return flase可选可填
public override bool GetStandardValuesExclusive(ITypeDescriptorContext context)
{
return false;
}
}
弹出窗体的比较麻烦(要用到UITypeEdit,还有要实现ForeColor那种选好颜色会显示一个小方框在属性框中表示颜色的功能也
是),我们在下一篇文章中再谈。另外,颜色选择框是[TypeConverter(typeof(WebColorConverter)],Enum可用TypeConverter
(typeof(EnumConverter))。
此外,我们还要关注一下这几个比较简单的Attribute:
[Bindable(true/false)],绑定数据到属性是否有意义,不过你设为false,用户一样可以在.aspx文件中输入表达式要把属性和一个数
据绑定表达式关联起来。(关于数据绑定,也是后话)
[DefaultEvent("Click")],双击控件,进入.cs文件,并开始编辑Click事件代码。
[DefaultProperty("Text")],选择控件,PropertyGrid把Text属性高亮显示。
[EditorBrowsable(EditorBrowableState.Always/Advanced/Never)],代码编辑器(不是后台代码编辑器,是指aspx文件的)是否为属
性、方法、事件提供IntelliSence支持,Default为Always,Advanced只用于VB.net,在用户选择查看高级成员时提供IntelliSence,
Never是不浏览IntelliSence信息。(我举不出例子这个在哪用过)
[DefaultValue(PropertyType.ProperDefaultValue)],设属性的默认值,注意默认值的类型对应属性的类型,如BorderStyle属性的默认
值你可以设[DefaultValue(BorderStyle.NotSet)]而不要写成了[DefaultValue("NotSet")]
接下来的文章,我们来看看:
序列化的属性是字符串,怎么样和真正的属性类型进行交互------TypeConverter
怎样更改默认的控件分析逻辑------PersistChildren(false)和ControlBuilder来定制ASP.net对控件标签对中的内容的分析