在使用系统控件的时候我们经常看见和使用控件的右上角的一个三角型的图标 ,点击之后弹出一个菜单,标题是“XXXX 任务”,里面提供了好多方便有用的设置。但是我们自己写的自定义控件中却没有,下面就让自己的UserControl也有这个功能。

想实现功能首先要知道功能的名称吧,不然想去Google一下都不知道要用什么关键字 :D 
这个功能叫做“智能标记 smart tag panel“。
今天以最常见的”在父容器中停靠“功能来演示一下如何让自定义控件实现智能标记功能。
一、正所谓”工欲善其事,必先利其器“,首先要引入一个库文件”System.Design“。
二、在自定义控件的命名空间下定义一个类,集成ControlDesigner类。(我自定义的控件叫做AdSchedule,所以给类起名AdScheduleDesigner)

想实现功能首先要知道功能的名称吧,不然想去Google一下都不知道要用什么关键字 :D 这个功能叫做“智能标记 smart tag panel“。
今天以最常见的”在父容器中停靠“功能来演示一下如何让自定义控件实现智能标记功能。
一、正所谓”工欲善其事,必先利其器“,首先要引入一个库文件”System.Design“。
二、在自定义控件的命名空间下定义一个类,集成ControlDesigner类。(我自定义的控件叫做AdSchedule,所以给类起名AdScheduleDesigner)

1 public class AdScheduleDesigner : System.Windows.Forms.Design.ControlDesigner

 

这个类的作用是”扩展 Control 的设计模式行为“,类中需要定义一个DesignerActionListCollection类型的属性。

1 private DesignerActionListCollection actionLists;
2  public override DesignerActionListCollection ActionLists
3 {
4 get
5 {
6 if (null == actionLists)
7 {
8 actionLists = new DesignerActionListCollection();
9 actionLists.Add(new AdScheduleActionList(this.Component));
10 }
11 return actionLists;
12 }
13 }

 

三、再创建一个编写逻辑程序的类
1 public class AdScheduleActionList : System.ComponentModel.Design.DesignerActionList
2 {
3 private AdSchedule adSchedule;
4 private DesignerActionUIService designerActionUISvc = null;
5
6 public AdScheduleActionList(IComponent component) : base(component)
7 {
8 this.adSchedule = component as AdSchedule;
9
10 this.designerActionUISvc
         GetService(typeof(DesignerActionUIService)) as DesignerActionUIService;
11 }
12 }

 

四、在AdScheduleActionList类中重写GetSortedActionItems方法。

1 public override DesignerActionItemCollection GetSortedActionItems()
2 {
3 DesignerActionItemCollection items = new DesignerActionItemCollection();
4 items.Add(new DesignerActionMethodItem(this, "ParentComponentStop", "在父容器中停靠"));
5 return items;
6 }

 

其中DesignerActionMethodItem的构造方法有三个参数:
1、ActionList
2、要通过面板项调用的方法的名称,此方法是从 DesignerActionList 派生的类中的一个方法,其方法名区分大小写。
3、此项的面板文本。
这个函数写好之后就在AdScheduleActionList类中添加需要调用的方法。
1 public void ParentComponentStop()
2 {
3 componentLocation = adSchedule.Location;
4 componentSize = adSchedule.Size;
5
6 adSchedule.Dock = System.Windows.Forms.DockStyle.Fill;
7 adSchedule.Location = new System.Drawing.Point(0, 0);
8 }

 

五、就这么简单,智能标记已经可以用了。

 

点击以后窗口就可以在父容器中停靠,但是问题来了,如何取消停靠呢?

很简单就是修改GetSortedActionItems方法中的DesignerActionItemCollection。

这里我们还需要创建两个变量,在ParentComponentStop函数中赋值用来保存控件停靠前的位置和大小,以便取消的时候返回原来的样子。

1 public override DesignerActionItemCollection GetSortedActionItems()
2 {
3 DesignerActionItemCollection items = new DesignerActionItemCollection();
4 if (DockStyle.None == adSchedule.Dock)
5   items.Add(new DesignerActionMethodItem(this, "ParentComponentStop", "在父容器中停靠"));
6 else
7   items.Add(new DesignerActionMethodItem(this, "CancelParentComponentStop", "取消在父容器中停靠"));
8 return items;
9 }

 

1 public void CancelParentComponentStop()
2 {
3 if (null == componentLocation)
4 componentLocation = adSchedule.Location;
5 if (null == componentSize)
6 componentSize = adSchedule.Size;
7
8 adSchedule.Dock = DockStyle.None;
9 adSchedule.Location = componentLocation;
10 adSchedule.Size = componentSize;
11
12 designerActionUISvc.Refresh(this.Component);
13 }

 

还没有完,点击之后为什么还是“在父容器中停靠”?文字没有变化呢?

还记得designerActionUISvc这个变量吗?他用来缓存DesignerActionUIService,以实现DesigneractionList刷新功能。

在ParentComponentStop函数最后加上这句话

1 designerActionUISvc.Refresh(this.Component);

 

现在就大功告成了,喝杯咖啡自己欣赏一下吧。

 

这只是个简单的应用,简单的文字链接形式实现调用函数,其实在智能标记中可以实现很多功能。

大家可以参考一下MSDN,给DesignerActionItemCollection传入不同类型的值就会实现更多的操作。

下载源代码

 

参考MSDN文献:

演练:向 Windows 窗体组件添加智能标记

 

如何:向 Windows 窗体组件附加智能标记

posted on 2010-03-31 11:02  镭风  阅读(889)  评论(2编辑  收藏  举报