Clingingboy

<developer name=’'clingingboy">
<i:Interaction.Behaviors>
<clingingboy:madeControlBehavior />
</i:Interaction.Behaviors>
</developer>

博客园 首页 新随笔 联系 订阅 管理
  211 Posts :: 1 Stories :: 1440 Comments :: 484 Trackbacks
     上一篇简单的讲了从WebControl继承的控件(好象我讲的都是简单的,嘿嘿).本次讲的更简单,主题是是属性,只当分享经验,希望对大家有帮助

我们根据属性的不同表现形式,把其区分为简单属性和复杂属性

下面来看下属性的表现形式

简单属性表现形式如下,大家都很熟悉

<asp:TextBox ID="TextBox1" Text="textbox控件" runat="server"></asp:TextBox>

属性中含有子属性,称之为复杂对象,如Font属性
复杂属性的表现形式如下,

(1)连字符的表现形式
<asp:TextBox ID="TextBox1" Text="textbox控件" runat="server" Font-Bold="True"></asp:TextBox>

(2)内镶属性的表现形式,如定义样式

<asp:DataList ID="DataList1" runat="server">
            
<SelectedItemStyle />
            
<EditItemStyle />
        
</asp:DataList>

(3)内镶集合属性的表现形式,如DropDownList (先不介绍,大家可看MSDN)
<asp:DropDownList ID="DropDownList1" runat="server">
            
<asp:ListItem>x</asp:ListItem>
            
<asp:ListItem>xx</asp:ListItem>
            
<asp:ListItem>xxx</asp:ListItem>
        
</asp:DropDownList>

下面得好好看

1,复杂属性基本使用方法

请看我是怎么做的,关于下面看到了一些元数据,如果你不熟悉,请参考MSDN.

下面一段代码记录一个custom的信息.

1.1 定义枚举
using System;

namespace CustomComponents
{
    
/// <summary>
    
/// 职业
    
/// </summary>

    public enum Metier
    
{
        教师,程序员,作家
    }

}


1.2定义复杂属性

using System;
using System.ComponentModel;

namespace CustomComponents
{


    
/// <summary>
    
/// 地址集合
    
/// </summary>

    public class Address
    
{
        
private String street = null;
        
private String city = null;
        
private String state = null;
        
private String zip = null;

        
public String Street
        
{
            
get
            
{
                
return street;
            }

            
set
            
{
                street 
= value;
            }

        }



        
public String City
        
{
            
get
            
{
                
return city;
            }

            
set
            
{
                city 
= value;
            }

        }


        
public String State
        
{
            
get
            
{
                
return state;
            }

            
set
            
{
                state 
= value;
            }

        }


        
public String Zip
        
{
            
get
            
{
                
return zip;
            }

            
set
            
{
                zip 
= value;
            }

        }

    }

}



1.3 呈现控件



1.4 在asp.net页面定义控件,

发现问题:
属性不是有效属性,如下图



打开后台代码,输入如下代码检查属性,发现属性是存在的,如下图,再打开视图,发现控件能显示属性,唯一的就是不能认识属性为有效属性,在源视图也无法找到这几个属性.



1.5 解决1.4无法显示有效属性的问题,(其实以上的测试已经实现复杂属性了).

  解决方法:请在Custom类中的CustomAddress中加入一个元数据(元数据的解释请参考MSDN),如下

        [Description("地址集合")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        
public Address CustomAddress
        
{
            
get
            
{
                
return address;
            }

        }

再次打开源视图,发现编辑器已经支持此属性了,如下图,这样有点意思吧,呵呵



虽然源视图上已经支持这个复杂属性了,打开属性面板,发现属性面板并不支持这个复杂属性(因为我们比较懒,不喜欢在源视图里编辑属性,想直接在属性面板编辑属性,下面就称复杂属性是CustomAddress),我们想要达到的效果,是让CustomAddress属性跟Font属性一样(可以折叠)显示在面板上,如下图



发现问题:属性面板并不支持这个复杂属性

1.6 实现CustomAddress属性折叠效果

解决方法:
给Address类添加一个元数据,如下

[TypeConverter(typeof(ExpandableObjectConverter))]
    
public class Address
    
{. }

编译后,再次打开属性面板,发现CustomAddress属性已经支持折叠效果,如下图



试着在属性面板编辑CustomAddress的子属性,修改好子属性以后然后运行页面,发现子属性修改数据后无效

发现问题:在属性面板编辑复杂属性的子属性无效

1.7 解决属性面板编辑复杂属性的子属性无效的问题

解决方法:
为Address类的每个属性加上一个元数据,如下

        [NotifyParentProperty(true)]
        
public String Street
        
{
            
get
            
{
                
return street;
            }

            
set
            
{
                street 
= value;
            }

        }

编译后,回到原asp.net的页面,再次在属性面板里修改子属性,再次运行页面.发现修改后的数据生效了.

好了,以上代码就是连字符形式的复杂属性的实现,我们接着继续,我们希望把CustomAddress属性做为内镶属性使用,即如下代码的形式

        <custom:custom id="Custom1" runat="server" name="Clingingboy" CustomMetier="教师" Age="21">
         
<CustomAddress City="杭州" Street="不告诉你" State="中国" Zip="310000" />
         
</custom:custom>

发现问题:无法使用内镶属性

1.8 实现内镶属性

解决方法:在Custom类中给CustomAddress再加入一个元数据(第三个),如下

        [Description("地址集合")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [PersistenceMode(PersistenceMode.InnerProperty)]
        
public Address CustomAddress
        
{
            
get
            
{
                
return address;
            }

        }

打开源视图(请不要把原来的连字符属性去掉),在控件内部加入如下代码(编辑器已经支持此属性了)

        <custom:custom    
        CustomAddress
-Zip="3100001"  CustomAddress-City="杭州1" 
        CustomAddress
-State="中国1" CustomAddress-Street="不告诉你1"
         id
="Custom1" runat="server" name="Clingingboy" CustomMetier="教师" Age="21">
         
<CustomAddress City="杭州" Street="不告诉你" State="中国" Zip="310000" />
         
</custom:custom>

发现问题:查看属性面板,再次修改CustomAddress子属性,然后运行,发现修改后无效果,而且显示的数据仍然是连字符属性的数据(非内镶属性的)

1.9 让控件支持内镶属性

解决方法:
给Custom类添加元数据,如下代码

    [ParseChildren(true)]
    
public class Custom: Control
    
 }

编译后,再次测试发现属性显示的优先级发生了变化,在内镶属性存在的时候,显示内镶属性,若其中有子属性不存在,则显示连字符属性,大家可以适当更改内镶属性和连字符属性测试变化.

发现问题:在属性面板改变属性时,仍然无法使修改后的数据生效,且修改后,数据退回初始的数据,并且导致内镶属性消失

1.10 解决属性面板的问题

解决方法:
给Custom类再添加一个元数据,如下代码

    [ParseChildren(true)]
    [PersistChildren(
false)]
    
public class Custom: Control
    
 }

编译后再次修改属性面板的值,发现修改的是内镶属性的数据,而且这次修改后数据没有丢失,运行后也是修改后的效果.

好了,简单的讲完了.

总结下:上面刚开始到1.3为止,其实效果已经实现了,接下来都是添加元数据,添加以后给我们带来的是方便.以上解决问题的办法全是套用元数据.可能上面的元数据大家很熟悉,在MSDN里面字面解释的也很清楚,但你去试验过吗?我相信这样的试验可以让你明白的更加深刻.

这次讲的虽然很简单(难得我把这么简单的东西变的这么复杂),主要是学习学习方法了
但我还是希望对大家有帮助,上面如果哪里讲错了还请指出来^_^.

示例代码下载(请大家多修改):


参考文章:

ASP.NET 2.0服务器控件开发之简单属性

ASP.NET 2.0服务器控件开发之复杂属性
posted on 2006-08-08 21:12 Clingingboy 阅读(15631) 评论(68)  编辑 收藏 网摘 所属分类: B Asp.net组件开发

Feedback

非常好,条理清楚,期待你的下篇!
  回复  引用    

#2楼 2006-08-09 12:26 h[未注册用户]
关注
  回复  引用    

写的还真是详细啊,一步一步的,发现问题解决问题,你做it讲师肯定很好。
  回复  引用    

#4楼 2006-08-10 09:48 出走的影子      
写的顺序挺不错,最好能在文章最后把所有用到的Attribute集中列一下
  回复  引用  查看    

#5楼[楼主] 2006-08-10 10:53 Clingingboy      
我尽量努力,谢谢上面的各位
  回复  引用  查看    

#6楼 2006-09-11 15:12 WaxDoll[未注册用户]
看了你的文章,有些开窍....

我还在用1.1,但我想无论是1.1还是2.0,其原理都是一样的;

但是我想详细和你请教下,我的MSN:hrbzhengda@msn.com

或是QQ:99750095
希望能加我,不吝赐教:)谢谢

  回复  引用    

#7楼[楼主] 2006-09-11 19:19 Clingingboy      
谢谢夸奖了,希望你喜欢我写的东西
  回复  引用  查看    

#8楼 2006-09-20 13:14 飞飞[未注册用户]
net1.1中按如上方法做的效果:
<cc1:custom1 id="Custom12" runat="server" Age="1" CustomMetier="教师" NameText="11">
<CustomAddress Zip="11" Street="11" City="11" State="11"></CustomAddress>
</cc1:custom1>
提示:活动架构不支持元素CustomAddress.
Why?

  回复  引用    

#9楼[楼主] 2006-09-20 13:50 Clingingboy      
@飞飞

需先注册此控件呀

<%@ Register TagPrefix="custom"
Namespace="CustomComponents" %>

  回复  引用  查看    

#10楼 2006-09-20 15:55 飞飞[未注册用户]
我的是这样的
<%@ Register TagPrefix="cc1" Namespace="Custom" Assembly="Custom" %>

  回复  引用    

#11楼 2006-09-20 15:55 飞飞[未注册用户]
我的是这样的
<%@ Register TagPrefix="cc1" Namespace="Custom" Assembly="Custom" %>

  回复  引用    

#12楼[楼主] 2006-09-20 16:42 Clingingboy      
要把Assembly="Custom"去掉,如果直接把代码放在App_Code里的话
  回复  引用  查看    

真的没白看,你能用发现问题-->解决问题的形式来讲,很不错
  回复  引用    

#14楼 2006-09-20 17:47 飞飞[未注册用户]
非常感谢!!!
  回复  引用    

#15楼[楼主] 2006-09-20 19:19 Clingingboy      
@bachelor
谢谢

  回复  引用  查看    

#16楼 2006-10-07 16:40 努力学习.NET      
这篇写的比前几篇都要好,条理很清楚,辛苦了
  回复  引用  查看    

我用你的代码在.net2.0中实现"内镶属性"要报错.说类型Address不存在.但放在.net1.1上执行完全正确.是怎么回事呢?
  回复  引用    

#18楼[楼主] 2006-10-20 22:58 Clingingboy      
不会命名空间错了吧,你再试一次看看.应该可以的
  回复  引用  查看    

把我牙都咬不动的老问题给解决了。谢谢了哦
  回复  引用    

你好,

我也是看你这篇文章做的自定义服务器控件

你写的很好

我在做复杂属性的时候遇到了个问题

能帮我看看吗

http://community.csdn.net/Expert/topic/5117/5117325.xml?temp=6.480044E-02

非常感谢

  回复  引用    

#21楼 2006-11-28 09:19 gggg[未注册用户]
v2003,没有以上效果,为什么
  回复  引用    

#22楼[楼主] 2006-12-28 19:39 Clingingboy      
我是在vs2005环境下面的,可能2003确实有这样的问题
  回复  引用  查看    

#23楼 2007-02-09 10:18 ada[未注册用户]
完全達到了效果了哈~,你講的真的有水平,條理很清楚,很清楚,十分感謝你,繼續關注你
  回复  引用    

#24楼 2007-03-14 11:16 大剑师      
Wonderful,从没有如此明白过,呵呵
  回复  引用  查看    

#25楼 2007-03-27 21:04 jack[未注册用户]
写得很有条理性,我正在学,辛苦你了,给我们提供这么详细的讲解.
  回复  引用    

#26楼 2007-03-30 15:04 风[未注册用户]
写的太好了!
  回复  引用    

很棒,博主的这个系列让我受益匪浅!
谢谢!

  回复  引用    

#28楼 2007-04-24 11:09 刘欢[未注册用户]
CustomComponents.CustomComponents”中不存在类型名称“Address”

问问楼主。当我更改该控件的属性时,就会报以上错误,这怎么回事啊。
找了半天都找不出问题来。都是照你代码写的。

  回复  引用    

#29楼[楼主] 2007-04-24 21:04 Clingingboy      
@刘欢
重新启动ide看看

  回复  引用  查看    

#30楼 2007-05-10 19:25 晓风残月      
很有条理性的文章!
  回复  引用  查看    

#31楼 2007-05-23 16:41 Miky[未注册用户]
这一篇看起来一气呵成,痛快得很……
向楼主致敬!

  回复  引用    

#32楼 2007-06-26 09:41 hchuan[未注册用户]
我这几天在公司没得事情就天天到你的Blog来看你的文章,写的真是详尽,太好啊了,谢谢你啊,兄弟,好样的,希望你写出更多的控件系列文章!呵呵~~~
  回复  引用    

#33楼 2007-07-20 11:04 刘淼[未注册用户]
您好!
你的文章写的太好了,给予我很大的帮助,首先向您致敬并表示感谢。关于这篇文章我想请教个问题,我下载了您提供的代码,怎么将custom作为控件显示在工具箱中呢?

  回复  引用    

#34楼 2007-08-10 14:41 CsharpFish      
这篇写的很是详细,条理也很明了,继续发扬…… 支持……
继续往下看 ……

  回复  引用  查看    

听君一席话 胜读十年书
  回复  引用    

#36楼 2007-09-28 14:45 bimoo[未注册用户]
我在做类似Font属性这样的折叠效果的时,能实现折叠,但是在试图修改属性内容的时候,出现了一个非常奇怪的错误:“尝试读取或写入受保护的内存。这通常指示其他内存已损坏。”在此之前一直没出现过这个错误。而且代码的话,我也是照着博主的实例一步一步进行的。
----盼达人帮忙。
环境:vs2005(SP1)+ Win2003(SP1)
这个错误我在网上查了一下,也没找到合理的解决方法。
Email:lxcool@126.com

  回复  引用    

#37楼[楼主] 2007-09-28 14:58 Clingingboy      
@bimoo
这可能是IDE本身的问题,并非代码的问题.

  回复  引用  查看    

#38楼 2007-09-28 16:05 bimoo[未注册用户]
呵呵,感谢博主这么快就回复了。
这几天一直在研究你的系列文章,受益匪浅啊。多谢多谢!

对于上面这个问题,我现在已经解决了。
错误原因:
在你的代码中,CustomAddress这个属性的写法如下:
1:Address address = new Address();
2: [Description("地址集合")]
public Address CustomAddress
{
get
{
return address;
}
}
为了保存ViewState,我将所有的属性都改成了先读取ViewState,如下:
public Address CustomAddress
{
get
{
return ViewState["CustomAddress"] != null ? (Address)ViewState["CustomAddress"] : new Address();
}
}
对于其他的属性,比如Text是字符串形式,照着这样的写法,毫无问题,但是对于Adress这个类,用这种写法,就造成了之前我说的“尝试读取或写入受保护的内存。这通常指示其他内存已损坏”的错误。
我试着将Adress这个类序列化,但是问题依旧。
删除掉CustomAddress的读取ViewState的操作,问题得以解决。

但是新的问题又出来了,这个类不能保存到ViewState中去,那当页面回发,如何保存状态了?
我试着这样做:在Address类中读取ViewState
public class Address
{
// 因为在此处是不能直接使用ViewState的。
private StateBag ViewState = new StateBag();
public String Street
{
get
{
return ViewState["Street"] != null ? ViewState["Street"].ToString() : "";
}
set
{
ViewState["Street"] = value;
}
}
}
但是仍然不能保存其状态。
不知道以上设计中是哪里出现了问题。
唉。。。
埋下头,继续研究。

  回复  引用    

#39楼 2007-10-07 20:35 liyf[未注册用户]
楼主写得太好了,做个大学it方面的教授都可以了,支持,顶一下!
  回复  引用    

#40楼 2007-10-09 11:16 nare      
感谢楼主,正在学习中!
  回复  引用  查看    

#41楼 2007-12-03 17:34 为平[未注册用户]
你好 我想做一个属性 就像AJAX里面的Extend Control属性里面的Target Control ID那样有一个被指定控件类型的控件列表。
我查了一下网上有说在属性上面加这个
[IDReferenceProperty]
[TypeConverter(typeof(ControlIDConverter))]

但是它出来的是所有控件的列表。另外还有
[TypeConverter(typeof(ValidatedControlConverter))]
是可以被Validated的Control列表

我只需要一个页面上所有 Button的列表
这个需要怎么做呢?
谢谢

  回复  引用    

#42楼[楼主] 2007-12-10 16:03 Clingingboy      
@为平
要么自定义一个Converter,要么动态在后台获取到按钮后绑定

  回复  引用  查看    

#43楼 2007-12-12 09:01 为平[未注册用户]
你好
我还想问一下,我GridView想获取运行时自动产生出来的列如何获取?
如果是自动生成列的话我在GridView控件里面注册排序事件中获取Columns.Count是0
这个还有其他什么可以在控件里面获取产生的列的数量?
谢谢

  回复  引用    

#44楼 2007-12-20 21:05 阿鹏      
学习了.
如果能够详细的归纳下这些复杂的元数据.
并分析下,就太好不过了.

  回复  引用  查看    

#45楼 2008-01-09 15:55 igelf[未注册用户]
总的来说.这篇是前五篇最清晰.好懂.哈哈
  回复  引用    

楼主写的东西真好!太感谢了。
不过我在试您的程序的时候发觉。其实一个属于Name我不能在窗口中赋值,会直接和控件的ID联动。我把Name改名为UserName就可以用了,不知道是不是我自己设置错了。

  回复  引用    

#47楼 2008-04-07 17:18 zhouyou96      
强,不过把元数据在最后总结一下就更好了。
  回复  引用  查看    

#48楼 2008-04-25 00:08 Son[未注册用户]
好文章 我顶!
  回复  引用    

#49楼 2008-04-25 00:08 Son[未注册用户]
期待 做的更好!
  回复  引用    

#50楼 2008-04-25 00:09 Son[未注册用户]
定!
  回复  引用    

顶!!!!!
  回复  引用    

写的很好.喜欢楼主.
  回复  引用    

#53楼 2008-07-18 17:48 ︷起↘嚸.      
细节东西讲的很清楚,受益了
  回复  引用  查看    

#54楼 2008-08-11 16:50 丛林之王      
看的迷迷糊糊,可能是我以前没接触过这方面的东西,希望LZ多出点关于底层的东东!!~~~谢谢
  回复  引用  查看    

楼主你太N了

  回复  引用    

#56楼 2008-11-11 18:00 MythYsJh      
属性要怎样才能折叠啊,我在website和web application下都不能折叠
  回复  引用  查看    

#57楼[楼主] 2008-11-12 21:44 Clingingboy      
@MythYsJh
使用ExpandableObjectConverter类型转换器

  回复  引用  查看    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

[使用Ctrl+Enter键快速提交评论]

0 470980




相关文章:

相关链接: