今天你写控件了吗?----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对控件标签对中的内容的分析

属性编辑器

......

posted @ 2005-05-16 09:02 Think 阅读(10376) 评论(28) 编辑 收藏

 回复 引用   
#1楼2005-05-16 18:18 | mzl
强!
 回复 引用 查看   
#2楼[楼主]2005-05-17 09:06 | THIN(仁与渣)      
呵呵,没什么人回应,是不是写得挺乱,我写完之后也有一种乱的感觉,没前几篇容易消化,这篇里的东西有点多,所以可能不是每个人都有耐心看完。
其实在早几天我有空就在想这篇该怎么写,一直没有清晰的头绪,最后还是趁着周日晚上的一点空闲把它写出来,只是写的时候一动笔就罗罗嗦嗦出来这么多。

周六去西冲沙滩玩到周日下午,仅睡了两个小时就爬起来写这篇东西,虽然累,不过也是乐在其中。

 回复 引用 查看   
#3楼2005-05-17 10:44 | chengulv      
是太长了点, 我只看了看,还没时间去研究学习, 先标记一下。
 回复 引用 查看   
#4楼[楼主]2005-05-17 10:52 | THIN(仁与渣)      
其实长不是问题,主要是没有组织好内容,也没有仔细地推敲字句,该死!
 回复 引用 查看   
#5楼[楼主]2005-05-17 10:53 | THIN(仁与渣)      
不过内容还是有的,还是值得学控件开发的朋友一看的:)
 回复 引用 查看   
#6楼2005-05-19 08:31 | 極速麻醉      
我會繼續關注的。只不過有些東西看的不是很清楚。可能基礎太差了!
 回复 引用 查看   
#7楼[楼主]2005-05-19 08:59 | THIN(仁与渣)      
是写得有点不清晰,不好意思,
别的应该没什么,那个属性用下拉列表的是你要另建一个类,在这个类中重载几个函数,再在属性上用Attribute关联这个类。

 回复 引用 查看   
#8楼[楼主]2005-05-19 09:00 | THIN(仁与渣)      
真正写得好的东西,是能让尽量大部分看懂的,下一篇多花时间,争取写好。
 回复 引用 查看   
#9楼2005-05-24 00:00 | Learning .net      
写得很好。
比自己去msdn上找,再自己看强多了。
自己看msdn上,折腾了头天,觉得头都大了

 回复 引用   
#10楼2005-05-24 21:44 | 喜欢雨
写的很好啊
不过组织好一点就更好了....
学习中

 回复 引用 查看   
#11楼2005-06-14 11:46 | 一路奔波      
能写的再有条理点,再详细点就好了!谢谢
 回复 引用   
#12楼2005-06-14 11:58 | bingyu
我在做一个控件时,js代码中用到一个html中的控件,这个控件的id已经在html中定义过,可是在运行时却出现未定义的错误。怎么回事呢?请指教。
 回复 引用 查看   
#13楼[楼主]2005-06-14 12:03 | THIN      
这要看你的JS定义在哪,
如果是直接定义,要放在无素的后面,不然定义时元素还没有初始化。
最好的办法是放在body onload事件中。

 回复 引用   
#14楼2005-06-16 13:33 | dkhero
看不动了,这应该是我现阶段的极点了。不过我会顶下去的,再一次感谢各位!
 回复 引用   
#15楼2005-07-12 22:14 | xiaop[未注册用户]
确实到了一个点……~……~
原来的可能比较简单
这里开始有点难度!!~~~
忍住看……~……~

 回复 引用   
#16楼2005-07-13 09:11 | thin
呵呵,慢慢来,先写写简单的,练练手,再来看看复杂的,就成了。
 回复 引用 查看   
#17楼2005-09-23 10:51 | 垃圾猪      
好好看了一遍,不错
 回复 引用 查看   
#18楼2006-01-16 14:36 |       
支持
 回复 引用   
#19楼2006-02-21 12:35 | 忍渣[未注册用户]
好像在深圳见过你,HOHO!
写的不错,但是不懂控件开发

 回复 引用   
#20楼2006-07-06 09:31 | net2v[未注册用户]
上面代码最经典的注释是这一句

//return ture的话只能选,return flase可选可填

 回复 引用 查看   
#21楼[楼主]2006-07-06 10:46 | THIN      
@net2v
也许用DropDownList和ComboBox更好一点?

 回复 引用   
#22楼2007-08-08 15:52 | 牛鸿宇[未注册用户]
从第一章开始看没有停留一直看到这一章,刚开始还好可以看明白 现在有点迷糊了。不过仁渣老师写的还是蛮好的!
支持一下,再接再厉!

 回复 引用 查看   
#23楼2007-08-08 18:34 | PPBoy      
呵呵,尊敬下,不开你玩笑~~谢谢这么精彩的文章,可惜学晚了
 回复 引用   
#24楼2007-09-01 09:47 | amandag[未注册用户]
写的相当不错了
 回复 引用 查看   
#25楼2008-04-18 22:27 | .。oоΟ○〇      
我按照楼主的方法做的 ,但是还是没有显示下拉列表框,什么原因?
'-----------------------------------------------------
<Category("BuddyControl")> _
<TypeConverter(GetType(QHProject.PageControlsConverter))> _
<Bindable(False)> _
<Description("用于显示查询结果的地图控件")> _
Public Property BuddyMap() As String

Get
Dim o As Object = ViewState("Map")

If o Is Nothing Then
Return ""
Else
Return o.ToString()
End If

End Get
Set(ByVal value As String)
ViewState("Map") = value
End Set
End Property





Public Class PageControlsConverter
Inherits StringConverter

'构造函数
Public Sub New()

End Sub

'这个overrides说明要用下拉列表来编辑属性
'如果应调用 GetStandardValues 来查找对象支持的一组公共值,则为 true;否则,为 false。
Public Overrides Function GetStandardValuesSupported(ByVal context As ITypeDescriptorContext) As Boolean
Return True
End Function

'这个overrides返回下拉列表项
Public Overrides Function GetStandardValues(ByVal context As ITypeDescriptorContext) As System.ComponentModel.TypeConverter.StandardValuesCollection

Dim controls As ControlCollection = CType(context.Container.Components(0), System.Web.UI.Page).Controls

Dim controlsArray As ArrayList = New ArrayList()

For i As Integer = 0 To 10 'controls.Count - 1
Dim control As Control = controls(i)
If TypeOf control Is ESRI.ArcGIS.ADF.Web.UI.WebControls.Map Then
controlsArray.Add(control.ClientID)
End If

If control.HasControls Then
If TypeOf control Is ESRI.ArcGIS.ADF.Web.UI.WebControls.Map Then
controlsArray.Add(control.ClientID)
End If
End If
Next

Return New StandardValuesCollection(controlsArray)

End Function

'return ture的话只能选,return flase可选可填
Public Overrides Function GetStandardValuesExclusive(ByVal context As ITypeDescriptorContext) As Boolean
Return True
End Function

End Class

 回复 引用 查看   
#26楼2009-05-12 10:43 | Gary Gong      
楼主的语文功底还需锤炼啊.
呵呵,不过文章的确不错,很吃力的理解了.

 回复 引用 查看   
#27楼2009-07-10 20:50 | Hollen Zhao      
楼主写的都是很实用的经验

ControlCollection Controls = ((Page)context.Container.Components[0]).Controls;

这句很有价值

谢谢楼主分享。

大叔,我看懂鸟...

我是不是很帅-_-!