人立方关系搜索的silverlight控件外观定制揭秘

最近微软亚洲研究院的人立方关系搜索新发布了几个Silverlight的应用,包括关系图搜索,六度搜索和新闻时间轴。相信其绚丽的界面效果和赏心悦目的动画给大家留下了深刻印象。这里,我就尝试和大家一起来对这些应用进行揭谜,着重探讨siliverlight中三种定制控件外观的方法:

1)       在代码里面设置控件的风格

这种方法只能对控件的外观做一些简单的,轻量级的修改。比如这个半透明的矩形框:

 

 

我们只需要在代码里面这样写:

<Rectangle Fill="White" Opacity="0.1" Height="75" Canvas.Left="0" Canvas.Top="1" Margin="0,0,0,100" Width="20000"/>

其中Opacity属性就是设置矩形框的透明度,这里设为0.1,使其非常透明。可惜的是,这个矩形框在后来的设计中去掉了L

2)       把控件的风格写成资源文件

很多情况下,上面的方法就够用了。但是有时我们会遇到这样的情况:我们需要给多个控件设置类似的属性。仍然以上面的矩形框为例子,那代码就会是这样:

<Rectangle Fill="White" Opacity="0.1" Height="75" Canvas.Left="0" Canvas.Top="1" Margin="0,0,0,100" Width="2000"/>

<Rectangle Fill="White" Opacity="0.2" Height="75" Canvas.Left="0" Canvas.Top="1" Margin="0,0,0,100" Width="2000"/>

<Rectangle Fill="White" Opacity="0.3" Height="75" Canvas.Left="0" Canvas.Top="1" Margin="0,0,0,100" Width="2000"/>

<Rectangle Fill="White" Opacity="0.4" Height="75" Canvas.Left="0" Canvas.Top="1" Margin="0,0,0,100" Width="2000"/>

……

                有没有简单清晰的做法呢?有的!

我们仍然以六度搜索界面中的控件为例子:

图中白色的矩形框显示了两个人物之间的关系来源。 现在我们来设置其中黄色框中的两个名字的显示属性。它是一个TextBlock控件,代码里面我们这样写:

<TextBlock x:Name="textBlock" Text="{Binding Path=TitleB}" Style="{StaticResource TitleBlock}"/>

这个TextBlock的风格指向了名为”TitleBlock”的资源,其定义为:

<Style x:Key="TitleBlock" TargetType="TextBlock">

<Setter Property="FontFamily" Value="Microsoft YaHei"/>

<Setter Property="FontSize" Value="12"/>

<Setter Property="VerticalAlignment" Value="Center"/>

<Setter Property="HorizontalAlignment" Value="Left"/>

<Setter Property="Grid.Row" Value="1"/>

<Setter Property="Grid.Column" Value="1"/>

<Setter Property="Grid.ColumnSpan" Value="1"/>

</Style>

这样,多个控件可以共享这个名为TitleBlock的资源。我们可以通过修改这个资源文件,从而轻易的修改多个控件的外观。

3)       重写控件的模板

有时我们不得不面对复杂一些的情况:

 

请看图中黄色椭圆框中的控件,它们都是Button控件,但是其外观被完全改头换面了。我会选取其中三个控件作为例子在这里谈一谈:

3.1     箭头按钮

 

这个按钮的外形是个三角形,其定义为:

<Button x:Name="arrowUp" Canvas.Top="9" Canvas.Left="15" Canvas.ZIndex="99" Style="{StaticResource ArrowUpButton}" Click="ArrayUp_Click"/>

                它的Style指向了:

<Style x:Key="ArrowUpButton" TargetType="Button">

                <Setter Property="Cursor" Value="Hand"></Setter>

<Setter Property="Template">

<Setter.Value>

<ControlTemplate TargetType="Button">

                        <Grid>

                            <VisualStateManager.VisualStateGroups>

                                <VisualStateGroup x:Name="FocusStates">

                                    <VisualState x:Name="Unfocused"/>

                                    <VisualState x:Name="Focused"/>

                                </VisualStateGroup>

                                <VisualStateGroup x:Name="CommonStates">

                                    <VisualState x:Name="MouseOver"/>

                                    <VisualState x:Name="Pressed"/>

                                    <VisualState x:Name="Disabled"/>

                                    <VisualState x:Name="Normal"/>

                                </VisualStateGroup>

                            </VisualStateManager.VisualStateGroups>

 

                            <Polygon

                                                                            Points="0,5 5,0 10,5 0,5"

                                                                            Stroke="White"

                                                                            StrokeThickness="0">

                                <Polygon.Fill>

                                    <SolidColorBrush Color="White" Opacity="1"/>

                                </Polygon.Fill>

                            </Polygon>

                        </Grid>

                    </ControlTemplate>

                </Setter.Value>

            </Setter>

        </Style>

我们可以看到,这个控件的内部被放入了一个Polygon控件,所以这个箭头按钮会呈现这个Polygon所描绘的三角形。

 3.2       圆圈按钮

 

那么如果想做这个具有人立方特色的圆圈按钮,其步骤就可以分为如下几步:

3.2.1       把多个Ellipse控件封装到Button控件中

<Grid Height="auto" HorizontalAlignment="Center" VerticalAlignment="Center" Width="auto" IsHitTestVisible="True" Background="{x:Null}">                          

<Ellipse Margin="0,0,0,0" Stroke="{x:Null}" HorizontalAlignment="Center" VerticalAlignment="Center" Width="{TemplateBinding CircleButtonWidth1}" Height="{TemplateBinding CircleButtonHeight1}" IsHitTestVisible="False" x:Name="ellipse1" Fill="{TemplateBinding Ellipse1Fill}">

</Ellipse>

<Grid Margin="0,0,0,0" HorizontalAlignment="Center" Width="1024" Height="1024" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" x:Name="grid" Opacity="1" Background="{x:Null}" IsHitTestVisible="True">

<Ellipse Fill="{TemplateBinding Ellipse2Fill}" Stroke="{TemplateBinding Ellipse2Stroke}" Margin="0,0,0,0" Width="{TemplateBinding CircleButtonWidth2}" Height="{TemplateBinding CircleButtonHeight2}" x:Name="ellipse2" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center">

</Ellipse>

<Ellipse Margin="2,2,2,2" Fill="{TemplateBinding Ellipse3Fill}" Width="{TemplateBinding CircleButtonWidth3}" Height="{TemplateBinding CircleButtonHeight3}" x:Name="ellipse3" RenderTransformOrigin="0.5,0.5" HorizontalAlignment="Center" VerticalAlignment="Center">

</Ellipse>

<TextBlock Margin="0,0,0,0" FontFamily="Microsoft YaHei" FontSize="{TemplateBinding FontSize}" Foreground="#FFFFFFFF" HorizontalAlignment="Center" VerticalAlignment="Center" x:Name="textBlock" Text="{TemplateBinding Content}" RenderTransformOrigin="0.5,0.5" IsHitTestVisible="False">

</TextBlock>

</Grid>

</Grid>

3.2.2       注册一些属性,使得我们可以在代码里面动态的设置它们:

/// <summary>

/// The ellipse1 fill.

/// </summary> 

public Brush Ellipse1Fill

{

get

{

return (Brush)base.GetValue(Ellipse1FillProperty);

}

set

{

base.SetValue(Ellipse1FillProperty, value);

}

}

/// <summary>

/// Register property.

/// </summary>

public static readonly DependencyProperty Ellipse1FillProperty = DependencyProperty.Register("Ellipse1Fill", typeof(Brush), typeof(CircleButton), null);

这里我们就注册了名为Ellipse1Fill的属性,于是就可以设置它的值:

 

3.2.3       给其中部分Ellipse控件加上合适的storyboard,来处理鼠标的MouseOver事件

<VisualState x:Name="MouseOver">

<Storyboard>

<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">

<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1.5"/>

</DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">

<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1.5"/>

</DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">

<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1.5"/>

</DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="ellipse3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">

<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1.5"/>

</DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="textBlock" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)">

<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1.5"/>

</DoubleAnimationUsingKeyFrames>

<DoubleAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.0010000" Storyboard.TargetName="textBlock" Storyboard.TargetProperty="(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)">

<SplineDoubleKeyFrame KeyTime="00:00:00" Value="1.5"/>

</DoubleAnimationUsingKeyFrames>

</Storyboard>

</VisualState>

这样,这个具有人立方特色的圆圈按钮就完成了。

3.3       线段按钮

 

人立方的silverlight应用里面还有这样的线段按钮,它很细,但是很容易被鼠标点击到,具有很好的用户体验。其制作步骤也是类似的:

3.3.1.       封装两个Path控件到Button控件中:

a)         一个用来处理鼠标的Mouse over事件

<Path x:Name="outerPath" Stroke="White" StrokeThickness="10" Data="{TemplateBinding OuterPathData}" Opacity="0"></Path>

b)         一个用来显示这条线段

<Path x:Name="path" Stroke="White" StrokeThickness="1" Data="{TemplateBinding PathData}" Opacity="{TemplateBinding Opacity}"></Path>

3.3.2.       注册PathData属性

public Geometry PathData

{

get

                  {

                               return (Geometry)base.GetValue(PathDataProperty);

                  }

                  set

                  {

                               base.SetValue(PathDataProperty, value);

                  }

          }

public static readonly DependencyProperty PathDataProperty = DependencyProperty.Register("PathData", typeof(Geometry), typeof(PathButton), null);

 

3.3.3.       Path控件的Data属性设置为特殊的贝赛尔曲线,使得整个关系图看起来更具有立体感。

this.PathData = CreatePathData();

       private PathGeometry CreatePathData()

       {

            PathGeometry pathGeometry = new PathGeometry();

            PathFigure pathFigure = new PathFigure();

            pathFigure.StartPoint = leftPoint;

            pathGeometry.Figures.Add(pathFigure);

            Point midPoint = To2D.getPoint(leftPoint, rightPoint, centerPoint);

            QuadraticBezierSegment arcs = new QuadraticBezierSegment();

            arcs.Point1 = midPoint;

            arcs.Point2 = rightPoint;

            pathFigure.Segments.Add(arcs);

            return pathGeometry;

        }

3.3.4.       加入对应的storyboard

DoubleAnimation opacity = new DoubleAnimation();

opacity.From = 0;

         opacity.To = endOpacity;

         opacity.Duration = new Duration(TimeSpan.FromSeconds(1));

         Storyboard story = new Storyboard();

         story.Children.Add(opacity);

         Storyboard.SetTarget(opacity, this);

         Storyboard.SetTargetProperty(opacity, new PropertyPath("(UIElement.Opacity)"));

         story.BeginTime = TimeSpan.FromSeconds(beginTime);

         story.Completed += new EventHandler(AppearStory_Completed);

         story.Begin();

使得当鼠标hover到线段按钮上时,整条线段变亮。

 

结束语:

怎么样?Silverlight够简单够好用吧?我这里只是抛砖引玉,相信你在把silverlight应用到实际项目中时,会进一步体会到它的魅力^_^

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值