WPF实现简单的跑马灯效果
最近项目上要用到跑马灯的效果,和网上不太相同的是,网上大部分都是连续的,而我们要求的是不连续的。
也就是是,界面上就展示4项(展示项数可变),如果有7项要展示的话,则不断的在4个空格里左跳,当然,衔接上效果不是很好看。
然后,需要支持点击以后进行移除掉不再显示的内容。
效果如下:
思路大致如下:
1、最外层用一个viewbox,为了可以填充调用此控件的地方,这样可以方便自动拉伸
2、定义三个变量,一个是count值,是为了设定要展示的usercontrol的个数的,例如默认是4个,如效果图,当然,设置成5的话,就是5个了;一个list<grid>是为了放入展示控件的列表,一个list<usercontrol>是用来放所有要用于跑马灯里的控件的。
3、设置一个canvas,放入到最外层的viewbox中,用于跑马灯时候用(这也是常用的跑马灯控件canvas)
//给canvas设置一些属性 canvas_board.verticalalignment = verticalalignment.stretch; canvas_board.horizontalalignment = horizontalalignment.stretch; canvas_board.width = this.viewbox_main.actualwidth; canvas_board.height = this.viewbox_main.actualheight; canvas_board.cliptobounds = true; //用viewbox可以支持拉伸 this.viewbox_main.child = canvas_board;
4、将要循环的grid放入到canvas里,这里的grid的个数,要比展示的个数大一个,也就是count+1个值,因为滚动的时候,其实是在最外面有一个的,这样保证了循环的走动。至于两个控件之间的margin这个就是要设置grid的了,到时候控件是直接扔进grid里的
//循环将grid加入到要展示的列表里 for (int i = 0; i < uc_count + 1; i++) { grid grid = new grid(); grid.width = canvas_board.width / uc_count - 10; grid.height = canvas_board.height - 10; grid.margin = new thickness(5); this.canvas_board.children.add(grid); grid.setvalue(canvas.topproperty, 0.0); grid.setvalue(canvas.leftproperty, i * (grid.width + 10)); uclistforshow.add(grid); }
5、给每个grid增加一个动画效果,就是向左移动的效果
for (int i = 0; i < uclistforshow.count; i++) { //设置滚动时候的效果 doubleanimationusingkeyframes daukf_uc = new doubleanimationusingkeyframes(); lineardoublekeyframe k1_uc = new lineardoublekeyframe(i * (uclistforshow[i].width + 10), keytime.fromtimespan(timespan.fromseconds(2))); lineardoublekeyframe k2_uc = new lineardoublekeyframe((i - 1) * (uclistforshow[i].width + 10), keytime.fromtimespan(timespan.fromseconds(2.5))); daukf_uc.keyframes.add(k1_uc); daukf_uc.keyframes.add(k2_uc); storyboard_imgs.children.add(daukf_uc); storyboard.settarget(daukf_uc, uclistforshow[i]); storyboard.settargetproperty(daukf_uc, new propertypath("(canvas.left)")); }
6、滚动的时候,要计算usercontrol到底是添加到了哪个grid里面,也就是哪个控件作为了第一位。
我们设置一个索引值scroll_index,默认的时候,scroll_index=0,这是初始的状态,当滚动起来以后,scroll_index = scroll_index + 1 - uc_count;
然后,判断,循环的时候,是否是展示列表的末尾了,如果是的话,则要填充的控件是scroll_index %uclistsum.count(滚动索引,对总数直接取余数),如果不是的话则是scroll_index++ % uclistsum.count(滚动索引++,对总数直接取余数)
scroll_index = scroll_index + 1 - uc_count; for (int i = 0; i < uclistforshow.count; i++) { uclistforshow[i].setvalue(canvas.leftproperty, i * (uclistforshow[i].width + 10)); usercontrol uc; if (i == uclistforshow.count - 1) { uc = uclistsum[scroll_index % uclistsum.count]; } else { uc = uclistsum[scroll_index++ % uclistsum.count]; } if (uc.parent != null) { (uc.parent as grid).children.clear();//将usercontrol从原来的里面移除掉,要不然会抛错,usercontrol已属于另一个控件 } uclistforshow[i].children.clear(); uclistforshow[i].children.add(uc); //将隐藏按钮加入到grid里 button btn = new button(); btn.style = (dictionary["hidenstyle"] as style);//从样式文件里读取到button的样式 btn.tag = uclistforshow[i].children;//给tag赋值,这样方便查找 btn.click += btn_click;//注册隐藏事件 uclistforshow[i].children.add(btn); }
代码中,需要注意的是(uc.parent as grid).children.clear(),如果不移除的话,则会提示,已经属于另一个,所以,要从parent里面移除掉。
7、button的隐藏事件,当button点击以后,则要进行隐藏,其实也就是将总数里面,减除掉不再显示的那一项
private void btn_click(object sender, routedeventargs e) { if ((sender as button).tag != null) { uclistsum.remove((((sender as button).tag as uielementcollection)[0] as usercontrol)); } if (uclistsum.count == uc_count)//当列表数和要展示的数目相同的时候,就停止掉动画效果 { storyboard_imgs.completed -= storyboard_imgs_completed; storyboard_imgs.stop(); for (int i = 0; i < uc_count; i++) { uclistforshow[i].children.clear(); if (uclistsum[i].parent != null) { (uclistsum[i].parent as grid).children.clear(); } uclistforshow[i].children.add(uclistsum[i]); } return; } }
所有代码如下:
using system; using system.collections.generic; using system.linq; using system.text; using system.windows; using system.windows.controls; using system.windows.data; using system.windows.documents; using system.windows.input; using system.windows.media; using system.windows.media.animation; using system.windows.media.imaging; using system.windows.navigation; using system.windows.shapes; namespace marqueeusercontrol { /// <summary> /// marqueeuc.xaml 的交互逻辑 /// </summary> public partial class marqueeuc : usercontrol { resourcedictionary dictionary; public marqueeuc() { initializecomponent(); //读取样式文件 dictionary = new resourcedictionary { source = new uri("/marqueeusercontrol;component/marqueeusercontroldictionary.xaml", urikind.relative) }; } #region 属性 private int _uc_count = 0; /// <summary> /// 用来展示几个 /// </summary> public int uc_count { get { return _uc_count; } set { _uc_count = value; } } private list<grid> _uclistforshow = new list<grid>(); /// <summary> /// 用来展示的控件列表 /// </summary> private list<grid> uclistforshow { get { return _uclistforshow; } set { _uclistforshow = value; } } private list<usercontrol> _uclistsum = new list<usercontrol>(); /// <summary> /// 要添加的控件的列表 /// </summary> public list<usercontrol> uclistsum { get { return _uclistsum; } set { _uclistsum = value; } } #endregion canvas canvas_board = new canvas(); storyboard storyboard_imgs = new storyboard(); int scroll_index = 0;//滚动索引 double scroll_width;//滚动宽度 void gridlayout() { if (uc_count == 0)//如果这个值没有赋值的话,则默认显示四个 { uc_count = 4; } //给canvas设置一些属性 canvas_board.verticalalignment = verticalalignment.stretch; canvas_board.horizontalalignment = horizontalalignment.stretch; canvas_board.width = this.viewbox_main.actualwidth; canvas_board.height = this.viewbox_main.actualheight; canvas_board.cliptobounds = true; //用viewbox可以支持拉伸 this.viewbox_main.child = canvas_board; //循环将grid加入到要展示的列表里 for (int i = 0; i < uc_count + 1; i++) { grid grid = new grid(); grid.width = canvas_board.width / uc_count - 10; grid.height = canvas_board.height - 10; grid.margin = new thickness(5); this.canvas_board.children.add(grid); grid.setvalue(canvas.topproperty, 0.0); grid.setvalue(canvas.leftproperty, i * (grid.width + 10)); uclistforshow.add(grid); } } void storyload() { for (int i = 0; i < uclistforshow.count; i++) {//设置滚动时候的效果 doubleanimationusingkeyframes daukf_uc = new doubleanimationusingkeyframes(); lineardoublekeyframe k1_uc = new lineardoublekeyframe(i * (uclistforshow[i].width + 10), keytime.fromtimespan(timespan.fromseconds(2))); lineardoublekeyframe k2_uc = new lineardoublekeyframe((i - 1) * (uclistforshow[i].width + 10), keytime.fromtimespan(timespan.fromseconds(2.5))); daukf_uc.keyframes.add(k1_uc); daukf_uc.keyframes.add(k2_uc); storyboard_imgs.children.add(daukf_uc); storyboard.settarget(daukf_uc, uclistforshow[i]); storyboard.settargetproperty(daukf_uc, new propertypath("(canvas.left)")); } storyboard_imgs.fillbehavior = fillbehavior.stop; storyboard_imgs.completed += storyboard_imgs_completed; storyboard_imgs.begin(); } private void storyboard_imgs_completed(object sender, eventargs e) { scroll_index = scroll_index + 1 - uc_count; for (int i = 0; i < uclistforshow.count; i++) { uclistforshow[i].setvalue(canvas.leftproperty, i * (uclistforshow[i].width + 10)); usercontrol uc; if (i == uclistforshow.count - 1) { uc = uclistsum[scroll_index % uclistsum.count]; } else { uc = uclistsum[scroll_index++ % uclistsum.count]; } if (uc.parent != null) { (uc.parent as grid).children.clear();//将usercontrol从原来的里面移除掉,要不然会抛错,usercontrol已属于另一个控件 } uclistforshow[i].children.clear(); uclistforshow[i].children.add(uc); //将隐藏按钮加入到grid里 button btn = new button(); btn.style = (dictionary["hidenstyle"] as style);//从样式文件里读取到button的样式 btn.tag = uclistforshow[i].children;//给tag赋值,这样方便查找 btn.click += btn_click;//注册隐藏事件 uclistforshow[i].children.add(btn); } storyboard_imgs.begin(); } private void btn_click(object sender, routedeventargs e) { if ((sender as button).tag != null) { uclistsum.remove((((sender as button).tag as uielementcollection)[0] as usercontrol)); } if (uclistsum.count == uc_count)//当列表数和要展示的数目相同的时候,就停止掉动画效果 { storyboard_imgs.completed -= storyboard_imgs_completed; storyboard_imgs.stop(); for (int i = 0; i < uc_count; i++) { uclistforshow[i].children.clear(); if (uclistsum[i].parent != null) { (uclistsum[i].parent as grid).children.clear(); } uclistforshow[i].children.add(uclistsum[i]); } return; } } public void startmar() { gridlayout(); scroll_width = this.canvas_board.width; for (int i = 0; i < uclistforshow.count; i++) { usercontrol uc; if (i == uclistforshow.count - 1) { uc = uclistsum[scroll_index % uclistsum.count]; } else { uc = uclistsum[scroll_index++ % uclistsum.count]; } if (uc.parent != null) { (uc.parent as grid).children.clear(); } uclistforshow[i].children.clear(); uclistforshow[i].children.add(uc); } storyload(); } private void grid_main_mouseleave(object sender, mouseeventargs e) { if (storyboard_imgs.getcurrentstate() == clockstate.stopped)//如果是停止的状态,则直接返回,不再起作用 { return; } if (storyboard_imgs.getispaused() == true)//如果是暂停状态的话,则开始 { storyboard_imgs.begin(); } } private void grid_main_mousemove(object sender, mouseeventargs e) { if (storyboard_imgs.getispaused() == false) { storyboard_imgs.pause(); } } } }
<resourcedictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:local="clr-namespace:marqueeusercontrol"> <style targettype="button" x:key="hidenstyle"> <setter property="background" value="transparent"/> <setter property="horizontalalignment" value="center"/> <setter property="verticalalignment" value="center"/> <setter property="width" value="25"/> <setter property="height" value="25"/> <setter property="borderbrush" value="transparent"/> <setter property="borderthickness" value="0"/> <setter property="template"><!--把image放到template里作为content显示,如果是单独给content设置图片的话,则只有一个按钮显示图片,其他的不显示--> <setter.value> <controltemplate targettype="{x:type button}"> <border> <image source="hiden.png"/> </border> </controltemplate> </setter.value> </setter> </style> </resourcedictionary>
没有解决的问题
想给button增加鼠标悬停的时候,显示,移除的时候隐藏,但是发现不好使,原因是当mouseover上去的时候,虽然visibility的值变了,但是只有到下一次的时候,button的值才被附上,而此时,已经mouseleave了,请哪位大神指导一下,看看这个显示和隐藏怎么做。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。