Clingingboy

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

博客园 首页 新随笔 联系 订阅 管理
  211 Posts :: 1 Stories :: 1440 Comments :: 484 Trackbacks
         上一篇讨论了类型转换器的使用,这次继续讨论讨论集合属性的使用

集合属性相信大家都很熟悉也很常用,如DropDownList,ListBox等控件

<asp:DropDownList ID="DropDownList1" runat="server">
            
<asp:ListItem>测试1</asp:ListItem>
            
<asp:ListItem>测试2</asp:ListItem>
            
<asp:ListItem>测试3</asp:ListItem>
        
</asp:DropDownList>


1.实现集合属性效果

经过前面几篇的学习,相信这一篇看起来已经相对简单了.我们要做的就是,先定义一个复杂属性,然后用迭代语句获取数组数据即可.

如果看过前面几篇就看看下面代码吧,相信看起来很简单,我们模仿一个DropDownList,为其属性添加背景属性,代码如下

先定义一个集合属性,如下

 public class DropItem
    
{
        
private string text;
        
private string value;
        
private Color backColor;

        [
         Category(
"Behavior"),
         DefaultValue(
""),
         Description(
"项文本"),
         NotifyParentProperty(
true),
         ]
        
public String Text
        
{
            
get
            
{
                
return text;
            }

            
set
            
{
                text 
= value;
            }

        }


        [
        Category(
"Behavior"),
        DefaultValue(
""),
        Description(
"项值"),
        NotifyParentProperty(
true),
        ]
        
public String Value
        
{
            
get
            
{
                
return value;
            }

            
set
            
{
                
this.value = value;
            }

        }


        [
        Category(
"Behavior"),
        DefaultValue(
""),
        Description(
"背景颜色"),
        NotifyParentProperty(
true),
        ]
        
public Color BackColor
        
{
            
get
            
{

                
return backColor;
            }

            
set
            
{
                backColor 
= value;
            }

        }


    }


 然后自定义一个控件,输出集合属性,如下代码

 [ParseChildren(true"DropItemList")]
   
public class DropColor:WebControl
    
{
       
private ArrayList dropItemList;

        [
        Category(
"Behavior"),
        Description(
"项集合"),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerDefaultProperty),
       
        ]

       
//定义集合属性
       public ArrayList DropItemList
        
{
            
get
            
{
                
if (dropItemList == null)
                
{
                    dropItemList 
= new ArrayList();
                }

                
return dropItemList;
            }

        }


       
//重写标签
       protected override HtmlTextWriterTag TagKey
       
{
           
get
           
{
               
return HtmlTextWriterTag.Select;
           }

       }

       
protected override void RenderContents(HtmlTextWriter writer)
       
{
           
//输出集合属性
           foreach (DropItem item in dropItemList)
           
{
               DropItem dr 
= item as DropItem;
               
if (dropItemList != null && dropItemList.Count > 0)
               
{
               
//颜色转换
               WebColorConverter wcc = new WebColorConverter();
               writer.AddAttribute(HtmlTextWriterAttribute.Value, dr.Value.ToString());
               writer.AddStyleAttribute(HtmlTextWriterStyle.BackgroundColor, wcc.ConvertToString(dr.BackColor));
               writer.RenderBeginTag(HtmlTextWriterTag.Option);
               writer.Write(dr.Text.ToString());
               writer.RenderEndTag();
               }

           }

           
base.RenderContents(writer);
       }

    }


上面代码注意颜色类型之间的转换,以下为HTML代码

<custom:DropColor ID="DropColor1" runat="server" ForeColor="White">
        
<custom:DropItem BackColor="Yellow" Text="黄色" Value="yellow" />
        
<custom:DropItem BackColor="Red" Text="红色" Value="red" />
        
<custom:DropItem BackColor="Blue" Text="蓝色" Value="blue" />
        
<custom:DropItem BackColor="Green" Text="绿色" Value="green" />
        
<custom:DropItem BackColor="Black" Text="黑色" Value="Black" />
        
</custom:DropColor>


输出以后的效果如下图




效果还不错吧,而且挺实用的.

2.定义编辑器

大家一般在添加集合属性的时候往往会在.net自带的编辑器中添加数据,这样可以提高效果,不用在HTML视图添加数据.如下图




我们也可以为其添加自定义的编辑器,其实我们一直在用.net自带的编辑器,我们称之为 UI编辑器或视图编辑器,如颜色,时间,超级链接等,大家该有所体会

其编辑器的基类为位于System.Drawing.Design命名空间的UITypeEditor,很多UI编辑器都从此类派生,有兴趣的可以去了解下这个类.

你们如何使用使用UI编辑器呢?也跟上一篇讲的类型转换器一样,你先要定义一个UI编辑器,然后与相关属性关联起来.

因为所定义的是一个集合类,而.net已经为我们提供了一个集合编辑器的CollectionEditor类,其已经为我们做了很多工作了,我们最简单的只需重写几个方法即可.具体其他属性和方法请参考MSDN,如下代码

    public class DropItemEditor : CollectionEditor
    
{
        
public DropItemEditor(Type type)
            : 
base(type)
        
{
        }

        
//一次可否选择多项
        protected override bool CanSelectMultipleInstances()
        
{
            
return false;
        }


        
//获取此集合包含的数据类型
        protected override Type CreateCollectionItemType()
        
{
            
return typeof(DropItem);
        }

    }


然后把集合属性与编辑器关联起来,添加了一个EditorAttribute,第一个参数为指定的编辑器类型,第二个为基本类型

        [
        Category(
"Behavior"),
        Description(
"项集合"),
        DesignerSerializationVisibility(
            DesignerSerializationVisibility.Content),
        PersistenceMode(PersistenceMode.InnerDefaultProperty),
        Editor(
typeof(DropItemEditor), typeof(UITypeEditor)),
        ]
       
//定义集合属性
       public ArrayList DropItemList
        
{
            
get
            
{
                
if (dropItemList == null)
                
{
                    dropItemList 
= new ArrayList();
                }

                
return dropItemList;
            }

        }



然后再来看下效果,这样就方面很多了.



如果还不想看到编辑器里的CustomComponents的命名空间的话,你可以像上一篇一样自定义一个类型转换器,代码如下:



然后还是照着步骤把属性与其关联起来

  [TypeConverter(typeof(DropItemConverter))]
    
public class DropItem
    
{
    }


再来看下效果




好了,这回讲的比较简单又实用,希望对大家有帮助.大家同时也可以参考MSDN里的例子,下面的示例代码下载我也加上了MSDN的例子.
已经写了10篇了,我们应该有些基础了,我想大家该可以做出一些简单实用的控件了.

示例代码下载
posted on 2006-09-16 15:20 Clingingboy 阅读(9775) 评论(47)  编辑 收藏 网摘 所属分类: B Asp.net组件开发

Feedback

GOOD!!
  回复  引用    

受益。
  回复  引用    

#3楼 2007-02-12 11:19 jacky[未注册用户]
Element 'DropItem' is not a known element. This can occur if there is a compilation error in the Web site. E:\demo\code10\ch10\drop.aspx 20

为什么出现这个错误啊?reference应该都是正确的

  回复  引用    

#4楼 2007-03-02 08:31 Bryant      
请问下:
CollectionEditor这个在我VS中怎么找不到
在msdn中可以找到是在System.ComponentModel.Design 命名空间下
不知怎么回事

  回复  引用  查看    

#5楼[楼主] 2007-03-02 09:25 Clingingboy      
可能没有引用System.Design程序集
  回复  引用  查看    

#6楼 2007-03-02 14:27 Bryant      
好像没有System.Design这个程序集
  回复  引用  查看    

#7楼 2007-05-17 10:24 刘欢[未注册用户]
不好意思,有个问题问下子作者!

我做了一个asp.net服务器控件(复合控件),当拖到Web页面的时候,为什么不能通过鼠标拖动设置它的大小啊?

当我修改了该控件的布局位置之后,它在Web页面中还是不能任意拖动。

这个是什么原因,有解决的办法吗?

  回复  引用    

#8楼[楼主] 2007-05-17 10:44 Clingingboy      
@刘欢
1.无法通过鼠标拖动设置它的大小是设计器的原因,这个可以通过修改设计时支持达到效果,但好象默认情况下是可以设置大小的...

2.无法在Web页面中任意拖动是因为IDE设置的原因,这个可以通过选项来设置.具体在哪我也忘了,呵呵.你可以在style样式中加个定位的css就可以拖了,但这个好象是vs2003的做法,现在好象不推荐这样子

  回复  引用  查看    

#9楼 2007-05-17 15:40 刘欢[未注册用户]
谢谢你。第一个问题已经解决了。

第二个问题在vs2005中可以通过设置来达到在Web面中拖动,但是这种设置只能对.net本身有的控件起作用,同样的设置对我们的自定义控件就没有作用了。
我想会不会还是我们设计控件的时候出的问题啊?

具体设置是否样的:选中你要设置的控件,然后选
工具->选项->HTML设计器->CSS定位->定位选项勾选上,然后选绝对定位
就可以了。

  回复  引用    

您好,请问我按照上面的代码把相关的类放在一个cs文件里编译成功,但是我一旦把他拖到页面上后就提示“发生了未处理的异常,未将对象引用设置的对象的实例”。请楼主帮帮我好吗?谢谢了
  回复  引用    

#11楼[楼主] 2007-05-25 17:15 Clingingboy      
@zxsy
重新启动ide试试

  回复  引用  查看    

CollectionEditor这个在我VS中怎么找不到
在msdn中可以找到是在System.ComponentModel.Design 命名空间下
不知怎么回事
我把你的源吗编译,也老实说CollectionEditor缺少引用,楼主帮忙解决啊
谢谢

  回复  引用    

@王春鹏
是因为你的dll文件没有引用进来呀。好像是system.design.dll吧。呵呵。

  回复  引用    

楼主,我都试过了,可是不知道为什么就是不行,编译一点问题都没有,只要一把生成的控件拖入页面就会报,呈现控件时出错:发生了未处理的异常,未将对象引用设置的对象的实例。难道我这个也是因为少dll文件吗?帮帮忙吧。
  回复  引用    

#15楼[楼主] 2007-05-28 15:09 Clingingboy      
@zxsy
看这篇吧
http://www.cnblogs.com/Clingingboy/archive/2007/05/22/754921.html" target="_new">http://www.cnblogs.com/Clingingboy/archive/2007/05/22/754921.html
定义一个集合类型会好点

  回复  引用  查看    

谢谢楼主 啊,问题解决.哈哈

  回复  引用    

楼主我知道为什么会出现错误了。最开始是因为没有附上初值,所以会提示控件呈现错误,
(当时控件在html端的标签为:
<cc1:DropColor ID="DropColor3" runat="server" ></cc1:DropColor>)
当我附上初值后,
(这时控件在html端的标签为:
<cc1:DropColor ID="DropColor3" runat="server" >
<cc1:DropItem BackColor="255, 128, 128" Text="1234" Value="5" />
</cc1:DropColor>)
这个问题解决了。
但是当我向属性集里增加新的属性时,控件又变成了呈现错误的样子,不过当我点击确定以后就没有问题了。
请问楼主这个有没有什么好办法吗?

  回复  引用    

#18楼[楼主] 2007-05-29 22:43 Clingingboy      
@zxsy
恩,以前我也遇到过这样的问题,没深究,可能是因为集合对象未初始化,在构造函数里初始化试试

  回复  引用  查看    

楼主好,我又来了
有个问题,我同时定义了两个集合属性与编辑器
一个是ParasList
另一个是FieldList
但是我在前面设置的prseChildren(true, "ParasList"),
结果我的FieldList编辑器中始终找不到数据
数据都跑道ParasList里去了
所以我想问问
这样定义两个集合属性与编辑器
谢谢啊


  回复  引用    

@王春鹏
不要设置prseChildren(true, "ParasList")
直接
prseChildren(true)
还是看我那边集合属性的随笔...

  回复  引用    

但是如果不设置prseChildren(true, "ParasList")
它总是说不具备ParasList ,FieldList 的公共属性
晕啊.我对底层不太熟悉.老实出问题.
还忘楼主多多谅解,多多帮助.
谢谢啊



  回复  引用    

#22楼[楼主] 2007-06-05 09:23 Clingingboy      
@王春鹏
prseChildren(true)

属性集合
[PersistenceMode(PersistenceMode.InnerDefaultProperty),
DesignerSerializationVisibility(DesignerSerializationVisibility.Content),
Category("Behavior")]

  回复  引用  查看    

你在啊,马上试试看哈
  回复  引用    

我是象你那样写的.
#region //参数编辑器
private ArrayList parasList;
[Category("参数配置")]
[
Description("参数编辑器"),
DesignerSerializationVisibility(
DesignerSerializationVisibility.Content),
Editor(typeof(ParasCollectEditor), typeof(UITypeEditor)),
PersistenceMode(PersistenceMode.InnerDefaultProperty)
]
public ArrayList ParasList
{
get
{
if (parasList == null)
{
parasList = new ArrayList();
}

//返回一个参数数组
return parasList;
}
}
#endregion

#region //字段参数编辑器
private ArrayList fieldList;
[Category("参数配置")]
[
Description("参数编辑器"),
DesignerSerializationVisibility(
DesignerSerializationVisibility.Content),
Editor(typeof(FieldItemEdit), typeof(UITypeEditor)),
PersistenceMode(PersistenceMode.InnerDefaultProperty)
]
public ArrayList FieldList
{
get
{
if (fieldList == null)
{
fieldList = new ArrayList();
}

//返回一个参数数组
return fieldList;
}
}
#endregion
控件属性:
/// <summary>
/// WebDataList 的摘要说明
/// </summary>
[
AspNetHostingPermission(SecurityAction.Demand,
Level = AspNetHostingPermissionLevel.Minimal),
AspNetHostingPermission(SecurityAction.InheritanceDemand,
Level = AspNetHostingPermissionLevel.Minimal),
ParseChildren(true),
ToolboxData(
"<{0}:WebDataList runat=\"server\"> </{0}:WebDataList>")
]
就抱不具备ParasList ,FieldList 的公共属性


  回复  引用    

#25楼[楼主] 2007-06-05 10:19 Clingingboy      
PersistenceMode.InnerDefaultProperty这个错了
  回复  引用  查看    

#26楼[楼主] 2007-06-05 10:19 Clingingboy      
不要用默认的
  回复  引用  查看    

#27楼[楼主] 2007-06-05 10:20 Clingingboy      
看这里
http://www.cnblogs.com/Clingingboy/archive/2007/05/22/754921.html" target="_new">http://www.cnblogs.com/Clingingboy/archive/2007/05/22/754921.html

  回复  引用  查看    

太感谢楼主了
果然是这个错了
谢谢
谢谢
谢谢
谢谢
谢谢
谢谢
谢谢
谢谢
谢谢
谢谢
谢谢
谢谢
给了我很多指点
期待你出书哦.我一定第一个买
都不知道该怎么感谢你
哈哈哈

  回复  引用    

#29楼 2007-07-01 10:43 WDFrog[未注册用户]
非常感谢楼主,有这么好的一系列文章!,
我对这里的一段代码比较困惑
public class DropItemConverter : ExpandableObjectConverter
中的
public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture,
object value)
{
if (value == null)
{
return new DropItem();
}
if (value is string)
{
string s = (string)value;
if (s.Length == 0)
{
return new DropItem();
}
return "DropItem"; //这里为什么返回一个字符串不是要DropItem类型吗?

}
return base.ConvertFrom(context, culture, value);
}

  回复  引用    

#30楼 2007-07-05 00:43 king[未注册用户]
我用你的控件,在后台怎样获取选中项的值呀,象selectitem.text发现是空值
,我想获取其中选中的dropitem的text和value值

  回复  引用    

#31楼[楼主] 2007-07-05 08:36 Clingingboy      
@king
这个没这个功能,需要再加进去

  回复  引用  查看    

#32楼 2007-08-05 18:28 Chl[未注册用户]
<custom:DropItem BackColor="Red" Text="红色" Value="red" >

sdfsdfsdf
<custom:DropItem>
我如果想实现这种型式的呢要咋搞呀.

  回复  引用    

#33楼 2007-08-11 12:20 feng[未注册用户]
<cc1:MyControl ID="MyControl 1" runat="server">
<cc1:CoulmnItem Field="" HeadText="zzz">
内容
</cc1:CoulmnItem>
</cc1:MyControl >
这是我的Control,通过集合编辑器增加CoulmnItem 时, 就构成了以下形式
<cc1:CoulmnItem Field="" HeadText="zzz" Content= "内容">
</cc1:CoulmnItem>
请问要怎么才能通过集合编辑器增加项时把内容放到<cc1:CoulmnItem></cc1:CoulmnItem>中呢?

  回复  引用    

@Clingingboy
就是啊,要在构造函数里面初始化,就不会出现了
就想我们编程的时候出现的错误提示“未设置对象之类的错误”一样,大概都是没有初始化的问题,

  回复  引用    

#35楼 2008-02-20 15:20 阿鹏      
大哥:一定要帮我啊
我写了一个类型你这个控件的功能 但我是派生至Control
类似DropColor : Control
则使用集合编辑器,可以添加但是一运行就为空了.

我调试了半天,还是老样子,但是改成派生至WebControl就可以了.

这把我弄迷糊了,

  回复  引用  查看    

#36楼[楼主] 2008-02-21 08:56 Clingingboy      
麻烦发示例给我,有时间帮你看看:)

clingingboy@gmail.com

  回复  引用  查看    

#37楼 2008-07-11 14:46 凡叶      
[quot]
如果还不想看到编辑器里的CustomComponents的命名空间的话,你可以像上一篇一样自定义一个类型转换器
[/quot]
不需要这样,只要重写类本身的.ToString()方法即可

  回复  引用  查看    

#38楼 2008-07-17 16:10 ylwlf[未注册用户]
<cc1:MyToolbar ID="MyToolbar1" runat="server">
<cc1:ItemNode Text="新建项1">
<cc1:ItemNode Text="新建项2">
</cc1:ItemNode>
</cc1:ItemNode>
</cc1:MyToolbar>
控件中有集合属性ItemNodes.
出现问题:新建项1能加进去.但其它的子节点新建项2不能加进去.
ItemNode.cs主要代码
public class ItemNode : IParserAccessor
{
internal ItemNodeCollection _Nodes;
public string Text
{
get
{
object o = ViewState["Text"];
return (o == null) ? string.Empty : o.ToString();
}
set
{
ViewState["Text"] = value;
}
}

[
Category("Data"),
DefaultValue(null),
MergableProperty(false),
Browsable(false),
PersistenceMode(PersistenceMode.InnerDefaultProperty)
]
public ItemNodeCollection Nodes
{
get { return _Nodes; }
}
}


ItemNodeCollection.cs主要代码
public class ItemNodeCollection : CollectionBase
{
public void Add(ItemNode _item)
{
// System.Windows.Forms.MessageBox.Show(_item.Nodes.Count.ToString());
List.Add(_item);
}

public void Remove(ItemNode _item)
{
List.Remove(_item);
}

public new int Count
{
get
{
return List.Count;
}
}

public ItemNode this[int index]
{
get
{
return (ItemNode)List[index];
}
}
}

MyToolbar.cs主要代码
public class MyToolbar : WebControl
{
private ItemNodeCollection _nodes = null;
public MyToolbar()
{
_nodes = new ItemNodeCollection(this);
}

[
DefaultValue(null),
MergableProperty(false),
PersistenceMode(PersistenceMode.InnerDefaultProperty)
]

public ItemNodeCollection Nodes
{
get
{

return _nodes;
}

}

protected override void RenderContents(HtmlTextWriter output)
{
output.Write("Text<br/>");
if ( Nodes .Count > 0)
{
output.Write(Nodes[0].Text + " ________子节点个数为: " + Nodes[0].Nodes.Count.ToString());
}


}
}

  回复  引用    

请教楼主,如何为自定义集合属性实现状态管理呢?楼主的QuickContacts控件示例实现了自定义集合属性却并未为其实现状态管理.假设集合项以声明方式添加到页中,或者如果已在代码中创建,则必须在回发时重新创建。如果有以下代码:
if (!Page.IsPostBack)
{
QuickContacts1.Contacts.Add(new Contact("1", "2", "3"));
QuickContacts1.Contacts.Add(new Contact("1", "2", "3"));
QuickContacts1.Contacts.Add(new Contact("1", "2", "3"));
}
那么在回发后重新加载页面时,在此代码段内添加的三项将丢失.

  回复  引用    

#40楼[楼主] 2008-12-24 02:04 Clingingboy      
@浣花居士
是的,为了独立把功能分开讲,所以这里没讲状态管理,可以继续往下看.

  回复  引用  查看    

UITypeEditor 类的名字空间为System.ComponentModel.Design;
不是你写的 System.Drawing.Design

很喜欢你的文章
呵呵
(我用的.net 1.1)

  回复  引用    




发表评论

昵称: [登录] [注册]

主页:

邮箱:(仅博主可见)

评论内容:

  登录  注册

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

0 505920 grZM23Q4HpM=



相关文章:

相关链接: