WindowsPhone自定义控件详解(二) - 模板类库分析
windowsphone自定义控件详解(一) - 控件类库分析
上一节主要分析了控件类库,控件类之间的继承关系,通过继承关系,可以知道一些属性,事件的源头和机制。
本节开始介绍模板类库,并加实例。
基类自定义时都要用到模板,在框架中所有的模板都是frameworktemplate的子类如下图,包括:
controltemplate
itemspaneltemplate
datatemplate
通过上述文字的分析,你已经可以理解为什么有上面的三种模板了吧。
下面分别来解释三种模板。
一、 模板类详解
继承关系:
由上图可知,控件对象模板,项集合模板和数据对象模板都是继承自frameworktemplate类,
1. controltemplate主要用于自定义控件的操作行为和视图结构的外观显示效果。如:当按钮按下时如何显示等,按钮上要不要同时显示图片和文本。
通过设置控件的template属性(继承自control)来应用自定义的controltemplate
2. itemspaneltemplate主要用于自定义带有列表项的控件中各子控件的布局外观显示效果,如:listbox中的列表项怎样对布局。
通过设置控件的itemspanel属性来应用自定义的itemspaneltemplate
3. datatemplate主要用于自定义内容控件中的数据视图效果,如:listbox中每一项显示什么数据。
通过设置控件的itemtemplate /contenttemplate属性来应用自定义的datatemplate,注意:一个控件上可能应用多个自定义模板,如:listbox设置listbox的列表项items为横向排列,设置每个列表项里布局和数据,这样就要设置listbox的itemspaneltemplate和datatemplate。
controltemplate类
定义控件的视图显示模板,从而可以对控件进行自定义。在模板内可以构建自己的控件对象树。
注意:
如果您正在定义一个控件模板来取代一个现有控件类的模板,则您用于定义控件模板内容的 xaml 应与现有的控件匹配。否则,该控件可能无法在用户界面中正常发挥作用。
不能将 controltemplate 应用于 usercontrol(前面有说明为什么)。
例如为 button 创建一个简单的 controltemplate。控件模板包含一个 grid 并指定以下行为:
· 当用户将鼠标悬停在 button 上方时,grid 在半秒之后从绿色变为红色。
· 当用户将鼠标移离按钮时,grid 立即变回到绿色。
[html] <controltemplate targettype="button">
<grid >
<visualstatemanager.visualstategroups>
<visualstategroup x:name="commonstates">
<visualstategroup.transitions>
<!--take one half second to trasition to the mouseover state.-->
<visualtransition to="mouseover" generatedduration="0:0:0.5"/>
</visualstategroup.transitions>
<visualstate x:name="normal" />
<!--change the solidcolorbrush, buttonbrush, to red when the
mouse is over the button.-->
<visualstate x:name="mouseover">
<storyboard>
<coloranimation storyboard.targetname="buttonbrush"
storyboard.targetproperty="color" to="red" />
</storyboard>
</visualstate>
</visualstategroup>
</visualstatemanager.visualstategroups>
<grid.background>
<solidcolorbrush x:name="buttonbrush" color="green"/>
</grid.background>
</grid>
</controltemplate>
<controltemplate targettype="button">
<grid >
<visualstatemanager.visualstategroups>
<visualstategroup x:name="commonstates">
<visualstategroup.transitions>
<!--take one half second to trasition to the mouseover state.-->
<visualtransition to="mouseover" generatedduration="0:0:0.5"/>
</visualstategroup.transitions>
<visualstate x:name="normal" />
<!--change the solidcolorbrush, buttonbrush, to red when the
mouse is over the button.-->
<visualstate x:name="mouseover">
<storyboard>
<coloranimation storyboard.targetname="buttonbrush"
storyboard.targetproperty="color" to="red" />
</storyboard>
</visualstate>
</visualstategroup>
</visualstatemanager.visualstategroups>
<grid.background>
<solidcolorbrush x:name="buttonbrush" color="green"/>
</grid.background>
</grid>
</controltemplate>
itemspaneltemplate 类
itemspaneltemplate定义itemscontrol中的item项布局的模板。itemscontrol 的默认值是一个指定 stackpanel的 itemspaneltemplate。例如:listbox是一个itemscontrol子控件,它的item项布局模板itemspaneltemplate为默认的stackpanel,而stackpanel默认布局是垂直布局,因此,默认的listbox的item项垂直布局的,当我们向listbox里添加item时,都是垂直列表形式,如果你想要自定义你的listbox风格为水平显示,那么将要自定义itemspaneltemplate里stackpanel为水平方向。
如下例,将listbox的风格改为水平子项显示方式。
模板xaml:
[html] <grid>
<grid.resources>
<style x:key="horizontallistboxstyle" targettype="listbox">
<setter property="itemspanel">
<setter.value>
<itemspaneltemplate>
<stackpanel orientation="horizontal"
verticalalignment="center"
horizontalalignment="center"/>
</itemspaneltemplate>
</setter.value>
</setter>
</style>
<src:items x:key="items"/>
</grid.resources>
<listbox itemssource="{staticresource items}"
style="{staticresource horizontallistboxstyle}"/>
</grid>
<grid>
<grid.resources>
<style x:key="horizontallistboxstyle" targettype="listbox">
<setter property="itemspanel">
<setter.value>
<itemspaneltemplate>
<stackpanel orientation="horizontal"
verticalalignment="center"
horizontalalignment="center"/>
</itemspaneltemplate>
</setter.value>
</setter>
</style>
<src:items x:key="items"/>
</grid.resources>
<listbox itemssource="{staticresource items}"
style="{staticresource horizontallistboxstyle}"/>
</grid>
c#代码:
[csharp] public class items :
system.collections.objectmodel.observablecollection<string>
{
public items()
{
add("item 1");
add("item 2");
add("item 3");
add("item 4");
add("item 5");
}
}
public class items :
system.collections.objectmodel.observablecollection<string>
{
public items()
{
add("item 1");
add("item 2");
add("item 3");
add("item 4");
add("item 5");
}
}
显示效果如下:
总结:
itemspaneltemplate主要用于带有item项的控件风格布局模板设置,常见的控件就是listbox,
datatemplate 类
用于定义内容控件内数据对象的可视结构模板。虽然内容控件只能包含一个uielement但是,它可以包含一个容器控件,从而可以间接的包含多个子控件,而datacontent就是为这些容器控件里的子控件进行布局的模板类。
下面的例子,自定了listbox中每一项中的ui如何表现。每一个item中包含四个水平布局的textblock控件,每个textblock控件都绑定了customers的属性。
xaml:
[html] <grid>
<grid.resources>
<src:customers x:key="customers"/>
</grid.resources>
<listbox itemssource="{staticresource customers}" width="350" margin="0,5,0,10">
<listbox.itemtemplate>
<datatemplate>
<stackpanel orientation="horizontal">
<textblock padding="5,0,5,0"
text="{binding firstname}" />
<textblock text="{binding lastname}" />
<textblock text=", " />
<textblock text="{binding address}" />
</stackpanel>
</datatemplate>
</listbox.itemtemplate>
</listbox>
</grid>
<grid>
<grid.resources>
<src:customers x:key="customers"/>
</grid.resources>
<listbox itemssource="{staticresource customers}" width="350" margin="0,5,0,10">
<listbox.itemtemplate>
<datatemplate>
<stackpanel orientation="horizontal">
<textblock padding="5,0,5,0"
text="{binding firstname}" />
<textblock text="{binding lastname}" />
<textblock text=", " />
<textblock text="{binding address}" />
</stackpanel>
</datatemplate>
</listbox.itemtemplate>
</listbox>
</grid>
c#:
[csharp] public class customer
{
public string firstname { get; set; }
public string lastname { get; set; }
public string address { get; set; }
public customer(string firstname, string lastname, string address)
{
this.firstname = firstname;
this.lastname = lastname;
this.address = address;
}
}
public class customers : observablecollection<customer>
{
public customers()
{
add(new customer("michael", "anderberg",
"12 north third street, apartment 45"));
add(new customer("chris", "ashton",
"34 west fifth street, apartment 67"));
add(new customer("cassie", "hicks",
"56 east seventh street, apartment 89"));
add(new customer("guido", "pica",
"78 south ninth street, apartment 10"));
}
}
public class customer
{
public string firstname { get; set; }
public string lastname { get; set; }
public string address { get; set; }
public customer(string firstname, string lastname, string address)
{
this.firstname = firstname;
this.lastname = lastname;
this.address = address;
}
}
public class customers : observablecollection<customer>
{
public customers()
{
add(new customer("michael", "anderberg",
"12 north third street, apartment 45"));
add(new customer("chris", "ashton",
"34 west fifth street, apartment 67"));
add(new customer("cassie", "hicks",
"56 east seventh street, apartment 89"));
add(new customer("guido", "pica",
"78 south ninth street, apartment 10"));
}
}
二、其它
datacontext类
datacontext是frameworkelement的属性,是object类型,用于获取或设置 frameworkelement 参与数据绑定时的数据上下文。也就是说它是被数据绑定的对象。
datacontext也就是第四代控件祖宗的属性(说实话,控件从第三代祖宗uielement开始才有了外观,有了点人样),
如果你给它绑定了数据源,clr就会从数据源里拿出对应数据用于显示,datacontext有传递性,如果外部包含控件设置了datacontext,被包含控件没有设置该属性,则被包含控件也可以使用外部包含控件的datacontext。
比如:
xaml:
[html] <phone:phoneapplicationpage.resources>
<local:weibodata x:key="myweibodata"/>
</phone:phoneapplicationpage.resources>
<grid x:name="layoutroot" background="transparent" datacontext="{staticresource myweibodata}">
<stackpanel grid.row="0" margin="12,17,0,28">
<textblock x:name="datetextblock" text="{binding weibodate}" >
<textblock x:name="titletextblock" text="{binding weibotitle}" />
</stackpanel>
</grid>
<phone:phoneapplicationpage.resources>
<local:weibodata x:key="myweibodata"/>
</phone:phoneapplicationpage.resources>
<grid x:name="layoutroot" background="transparent" datacontext="{staticresource myweibodata}">
<stackpanel grid.row="0" margin="12,17,0,28">
<textblock x:name="datetextblock" text="{binding weibodate}" >
<textblock x:name="titletextblock" text="{binding weibotitle}" />
</stackpanel>
</grid>
weibodata类中包含有weibodate属性和weibotitle属性,虽然没有指定两个textblock的绑定对象,但是它有grid控件的datacontext。
在后续两节,我们分别以这两节的知识,分享两个不错的例子:
自定义水印密码输入控件和下拉刷新控件。
注:上述两个控件经常使用并且方便快捷,经常用于微博等经常刷新的地方。
摘自 mr_raptor的专栏
上一篇: JS截图(html2canvas)