Helloj2ee的自定义ListBox(一),虽然很用心,但看出来反响不强烈。只能这一篇再给力一点。虽然评论很少,但是也看出一些讯息。
讯息之一,就是Helloj2ee的WPF看不懂。的确在这里写的不是基本的东西,而是对其WPF的相关基础概念掌握了之后,才能看的一个系列。自定义控件在《葵花宝典——WPF自学手册》一书中,是放到第六卷——华山之巅,足见其高阶。因此Helloj2ee在后面列出的参考文献,就很有价值了。因为您若是看不懂,不妨去参考相关文献,即便您没有葵花宝典一书,但总可以知道需要掌握的相关概念是什么,参阅其他书又何妨?
讯息之二,是提供的源码无法打开,那么Helloj2ee已经更新过。如果解压还是失败,您不妨在下面的回帖中告诉我。
说到给力,那么只有让这个控件在本章当中酷起来或者炫起来,才是给力的王道。
CircularPanel的布局之美
给力之前,Helloj2ee还是得枯燥一下,CircularPanel的那几个参数。第一个参数是CircularPanel的初始角度(InitialAngle)。
剩下的参数在该图中可以展现。Align属性实质是指的ListBoxItem的旋转点,Left表示外接矩形的左上角点,Center表示外接矩形的中心点,Right表示外接矩形的右下角点。而Radius指的是从圆心到旋转点的半径。AngleItem则是ListBoxItem之间的角度差。如下图所示:
ListBoxItem的外观
ListBoxItem的外观也需要通过模板来自定义。注意观察下图。实际上这样一个ListBoxItem是由如下五个元素组成的,分别是一个Path,三个Rectangle和一个TextBlock组成的。可能有人要问,为什么是三个Rectangle,实际上只是为了让这个边框一层一层更有层次感。
好了,我们来看看代码。
< Setter Property ="Template" >
< Setter.Value >
< ControlTemplate TargetType =" {x:Type ListBoxItem} " >
< Grid x:Name ="gridSwatch" Height ="180" Background ="#00000000" RenderTransformOrigin ="0.447,0.88" Width ="55" Cursor ="Hand" >
< Grid.RenderTransform >
< TransformGroup >
< ScaleTransform />
< SkewTransform />
< RotateTransform Angle ="90" />
< TranslateTransform X ="-65.75" Y ="-71.05" />
</ TransformGroup >
</ Grid.RenderTransform >
< Path x:Name ="overShape" Data ="M0,3.0000024 C0,1.3431468 1.3431457,0 3,0 L47,0 C48.656853,0 50,1.3431468 50,3.0000024 L50,185.00012 C50,186.65698 48.656853,188.00014 47,188.00014 C30.666666,190.16705 26.666666,222.49997 24.666666,231.5 C22.833332,222.49997 14,187.83371 3,188.00014 C1.3431457,188.00014 0,186.65698 0,185.00012 z" Fill ="#FF3C3C3C" Stroke =" {x:Null} " Margin ="0,-4,0,-47.5" IsHitTestVisible ="False" Visibility ="Collapsed" />
< Rectangle x:Name ="shadow3" Margin ="-4,-8,-4,-8" Fill ="#FF000000" Stroke =" {x:Null} " RadiusX ="7" RadiusY ="7" Opacity ="0.08" IsHitTestVisible ="False" />
< Rectangle x:Name ="shadow2" Margin ="-3,-7,-3,-7" Fill ="#FF000000" Stroke =" {x:Null} " RadiusX ="6" RadiusY ="6" Opacity ="0.08" IsHitTestVisible ="False" />
< Rectangle x:Name ="shadow1" Margin ="-2,-6,-2,-6" Fill ="#FF000000" Stroke =" {x:Null} " RadiusX ="5" RadiusY ="5" Opacity ="0.08" IsHitTestVisible ="False" />
< Rectangle x:Name ="whiteSwatch" Margin ="-1,-5,-1,-5" Fill ="#FFFFFFFF" Stroke =" {x:Null} " RadiusX ="4" RadiusY ="4" IsHitTestVisible ="False" />
< TextBlock FontSize ="22" FontFamily ="华文行楷" Text =" {Binding XPath=ImageText} " >
< TextBlock.RenderTransform >
< TransformGroup >
< RotateTransform Angle ="90" />
< TranslateTransform X ="30" Y ="30" />
</ TransformGroup >
</ TextBlock.RenderTransform >
</ TextBlock >
</ Grid >
</ ControlTemplate >
</ Setter.Value >
</ Setter >
</ Style >
上面的代码有几处,Helloj2ee简单说明一下。
(1)ListBoxItem自定义的模板,首先是一个Grid面板,该面板用了好几个变换,构成了一个变换组,尽管有诸如ScaleTransform等都未填写,但是这是为后面的动画埋下伏笔。
(2)这样的Path,的确难以用VS2010绘制出来,那么使用Expression Blend绘制就好,此外IsHitTestVisible属性设置为False,表明它并不接受用户的输入,只是作为一个基本的图元构成,同时设置了该Path在平时并不可见。
(3)注意TextBlock通过XPath属性设置了和XML文件的绑定。
好了再次运行程序,您看到了什么?
即使整个ListBox已经变样,但是它选择的效果可以说极其不好,因此我们必须再接再力,给它添加上一些动画效果。添加动画的效果主要靠控件模板的Trigger来触发了。大家先看代码,然后Helloj2ee再加以解释。
< EventTrigger RoutedEvent ="ListBoxItem.MouseEnter" >
< BeginStoryboard >
< Storyboard >
< DoubleAnimationUsingKeyFrames BeginTime ="00:00:00" Storyboard.TargetName ="gridSwatch" Storyboard.TargetProperty ="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" >
< SplineDoubleKeyFrame KeySpline ="0.5,0,0.5,1" KeyTime ="00:00:00.1000000" Value ="1.2" />
</ DoubleAnimationUsingKeyFrames >
< DoubleAnimationUsingKeyFrames BeginTime ="00:00:00" Storyboard.TargetName ="gridSwatch" Storyboard.TargetProperty ="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" >
< SplineDoubleKeyFrame KeySpline ="0.5,0,0.5,1" KeyTime ="00:00:00.1000000" Value ="1.2" />
</ DoubleAnimationUsingKeyFrames >
< ObjectAnimationUsingKeyFrames BeginTime ="00:00:00" Duration ="00:00:00.0010000" Storyboard.TargetName ="overShape" Storyboard.TargetProperty ="(UIElement.Visibility)" >
< DiscreteObjectKeyFrame KeyTime ="00:00:00" >
< DiscreteObjectKeyFrame.Value >
< Visibility > Visible </ Visibility >
</ DiscreteObjectKeyFrame.Value >
</ DiscreteObjectKeyFrame >
</ ObjectAnimationUsingKeyFrames >
</ Storyboard >
</ BeginStoryboard >
</ EventTrigger >
< EventTrigger RoutedEvent ="ListBoxItem.MouseLeave" >
< BeginStoryboard >
< Storyboard >
< DoubleAnimationUsingKeyFrames BeginTime ="00:00:00" Storyboard.TargetName ="gridSwatch" Storyboard.TargetProperty ="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)" >
< SplineDoubleKeyFrame KeySpline ="0.5,0,0.5,1" KeyTime ="00:00:00.2000000" Value ="1" />
</ DoubleAnimationUsingKeyFrames >
< DoubleAnimationUsingKeyFrames BeginTime ="00:00:00" Storyboard.TargetName ="gridSwatch" Storyboard.TargetProperty ="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)" >
< SplineDoubleKeyFrame KeySpline ="0.5,0,0.5,1" KeyTime ="00:00:00.2000000" Value ="1" />
</ DoubleAnimationUsingKeyFrames >
< ObjectAnimationUsingKeyFrames BeginTime ="00:00:00" Duration ="00:00:00.0010000" Storyboard.TargetName ="overShape" Storyboard.TargetProperty ="(UIElement.Visibility)" >
< DiscreteObjectKeyFrame KeyTime ="00:00:00" >
< DiscreteObjectKeyFrame.Value >
< Visibility > Collapsed </ Visibility >
</ DiscreteObjectKeyFrame.Value >
</ DiscreteObjectKeyFrame >
</ ObjectAnimationUsingKeyFrames >
</ Storyboard >
</ BeginStoryboard >
</ EventTrigger >
< Trigger Property ="IsMouseOver"
Value ="True" >
< Setter Property ="Panel.ZIndex"
Value ="1" />
</ Trigger >
</ ControlTemplate.Triggers >
主要是在MouseEnter和MouseLeave事件里做文章,当鼠标滑过某个ListBoxItem,我们通过改变它的ScaleTransform,让它变大。而离开ListBoxItem再通过改变ScaleTransform,让它恢复原状。比如像这样的语法,就未必有很多人能够写出来。请大家留心。
光是变换还是不够的,因为当鼠标滑过的时候,很有可能希望这个ListBoxItem凸现出来,那么要用到的就是Panel.ZIndex这个附加属性,通过改变这个值,让鼠标滑过的ListBoxItem凸现出来。
好了,现在的ListBoxItem已经完全变样了,但是还有美中不足。最为美中不足的就是ListBoxItem选中的时候,会出现一个虚框,这样的视觉效果确实很不好。
解决之道,又是一句话。
还有美中不足,比如选中某一个ListBoxItem,我们该作如何反应呢。这里helloj2ee就不再写这样的代码了。各位去尝试一下吧。
剩下的Helloj2ee需要做的是让这个对话框透明起来和加上中间的小圆点。中间的小圆点并不难加,让对话框完全透明也So Easy。那么Helloj2ee向各位奉上代码就好了。如果真的新手不知道该如何让不规则对话框透明的话,那么不妨参见葵花宝典第8章8.3.4节好了。
源代码:/Files/helloj2ee/ListBoxDemo3.rar