Blend ---- 给Button添加自定义状态模板(视觉状态管理)
一、首先按下图创建一个Silverlight for Windows Phone应用程序.
XAML代码如下
1 <phone:PhoneApplicationPage 2 x:Class="PhoneApp1.MainPage" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" 6 xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" 7 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 8 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 9 mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768" 10 FontFamily="{StaticResource PhoneFontFamilyNormal}" 11 FontSize="{StaticResource PhoneFontSizeNormal}" 12 Foreground="{StaticResource PhoneForegroundBrush}" 13 SupportedOrientations="Portrait" Orientation="Portrait" 14 shell:SystemTray.IsVisible="True"> 15 16 <!--LayoutRoot is the root grid where all page content is placed--> 17 <Grid x:Name="LayoutRoot" Background="Transparent"> 18 <Grid.RowDefinitions> 19 <RowDefinition Height="Auto"/> 20 <RowDefinition Height="*"/> 21 </Grid.RowDefinitions> 22 23 <!--TitlePanel contains the name of the application and page title--> 24 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> 25 <TextBlock x:Name="ApplicationTitle" Text="Blend Pro" Style="{StaticResource PhoneTextNormalStyle}"/> 26 <TextBlock x:Name="PageTitle" Text="Blend Pro" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 27 </StackPanel> 28 29 <!--ContentPanel - place additional content here--> 30 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 31 <Button Content="Button" Height="72" Name="CustButton" Width="160" /> 32 </Grid> 33 </Grid> 34 35 </phone:PhoneApplicationPage>
二、然后打开Blend修改Button
在中间的视图区域中选中Button,接着右击按钮,选择EditTemplate|Edit a Copy。系统将提示您为新模板命名,在本例中命名为BlendButton,并选择模板的归属位置。默认是PhoneApplicationPage,如果想在整个应用程序中重用该模板,则放到App.xaml文件中。单击OK后,Blend会为已有的Button模板复制一份副本,以便对其进行调整,然后打开该模板,进行更改。如图示已经被打开并处于编辑状态,因为它已经列出在Objects and Timeline 窗口的顶部。它的下面是模板内容,其中包含一个Grid,然后是一个名为ButtonBackgroun的Border,最后是一个名为foregroundContainer的ContentControl。
本例要对Button添加新的状态模板,所以我们在左上角的选项卡里选择States。在States窗口中,可以看到在新的CustomState模板中定义的各种状态。最重要的状态可能就是Base状态,它对应于初始状态或未修改的状态。除非被告知转到某个特定的状态,否则Button会永远处于这一状态下。而且我们还会看到两个不同的状态组。分别是CommonStates和FocusStates,在它们下面列出了其他不同的状态。在同一时刻每个分组内只能有一种状态被激活。
今天的示例要扩展该模板,来添加一个新的状态组并命名为PressedStatus,里面有两种状态HasNotBeenPressed和HasBeenPressed。点击States窗口顶部的Add state group按钮,当你单击次按钮时,会再States装口的底部创建一个新的状态组,然后该分组会被选中便于你可以立刻修改其名称,我们把它改为PressedStatus。接着点击位于PressedStatus分组节点右侧的Add state按钮。此时新的状态会出现在PressedStatus节点下,然后修改名字为HasNotBeenPressed。此为你可能注意到状态名字前面有一个红点,它表明你已经进入了StateRecording模式。这一点可以从主设计区中呈现出红色的边框和另一个红点以及一条内容为“HasNotBeenPressed state recording is on”的消息得到印证。然后重复这一步骤创建另外一种状态,命名为HasBeenPressed。
为了指示按钮已被按下,我们在按钮的右上角添加一个蓝色的点。它只在按钮处于HasBeenPressed状态时可见。不过,我们要再按钮的Base状态下添加该蓝点,而不是在按钮被按下时动态创建蓝点。该蓝点最初是隐藏的,当单击按钮时才可以看见。
要实现这一点,则要确保已经在States窗口中选中了Base状态,而且设计区周围没有红色边框。从Objects and Timeline窗口中选中【Grid】节点。打开Assets窗口并导航到Shapes,然后双击Ellipse从而在Grid中创建了Ellipse控件的实例。在Properties窗口中,将Fill和Stroke均设置成颜色为#FF0000FF的纯色画刷。将Ellipse的宽和高调为10.将HorizontalAlignment设置为Right,VerticalAlignment设置为Top,Margin的Top和Right两侧设置为20,。最后将Visibility设置为Collapsed以便使该点默认情况下不可见。
在States窗口中,选择HasBeenPressed状态。你会注意到红点和红色边框再次出现,以指示正在记录当前状态和Base状态之间的更改。在此阶段,只需要更改Visibility属性为Visible,以便每当HasBeenPressed状态被激活时显示蓝点。改过状态显示如下:
如果此时运行应用程序,你会发现蓝点从来没有出现过。这是因为你还没有指定Button应该在何时或者如何进入次状态。为此,我们在Button的Click事件里添加如下代码
1 if (CustButton.Tag.ToString() == "HasNotBeenPressed") 2 { 3 VisualStateManager.GoToState(CustButton, "HasBeenPressed", true); 4 CustButton.Tag = "HasBeenPressed"; 5 } 6 else 7 { 8 VisualStateManager.GoToState(CustButton, "HasNotBeenPressed", true); 9 CustButton.Tag = "HasNotBeenPressed"; 10 }
并给Button的Tag属性设置为HasNotBeenPressed。Button的XAML代码如下
1 <Button Content="Button" Height="72" Click="CustButton_Click" Tag="HasNotBeenPressed" Name="CustButton" Width="160" Style="{StaticResource CustomState}" />
点击第一次Button时的效果如下:
全部代码如下:
App.xaml
1 <!--Application Resources--> 2 <Application.Resources> 3 <Style x:Key="CustomState" TargetType="Button"> 4 <Setter Property="Background" Value="Transparent"/> 5 <Setter Property="BorderBrush" Value="{StaticResource PhoneForegroundBrush}"/> 6 <Setter Property="Foreground" Value="{StaticResource PhoneForegroundBrush}"/> 7 <Setter Property="BorderThickness" Value="{StaticResource PhoneBorderThickness}"/> 8 <Setter Property="FontFamily" Value="{StaticResource PhoneFontFamilySemiBold}"/> 9 <Setter Property="FontSize" Value="{StaticResource PhoneFontSizeMediumLarge}"/> 10 <Setter Property="Padding" Value="10,3,10,5"/> 11 <Setter Property="Template"> 12 <Setter.Value> 13 <ControlTemplate TargetType="Button"> 14 <Grid Background="Transparent"> 15 <VisualStateManager.VisualStateGroups> 16 <VisualStateGroup x:Name="CommonStates"> 17 <VisualState x:Name="Normal"/> 18 <VisualState x:Name="MouseOver"/> 19 <VisualState x:Name="Pressed"> 20 <Storyboard> 21 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer"> 22 <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneBackgroundBrush}"/> 23 </ObjectAnimationUsingKeyFrames> 24 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground"> 25 <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/> 26 </ObjectAnimationUsingKeyFrames> 27 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground"> 28 <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneForegroundBrush}"/> 29 </ObjectAnimationUsingKeyFrames> 30 </Storyboard> 31 </VisualState> 32 <VisualState x:Name="Disabled"> 33 <Storyboard> 34 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Foreground" Storyboard.TargetName="ContentContainer"> 35 <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/> 36 </ObjectAnimationUsingKeyFrames> 37 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="BorderBrush" Storyboard.TargetName="ButtonBackground"> 38 <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource PhoneDisabledBrush}"/> 39 </ObjectAnimationUsingKeyFrames> 40 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="Background" Storyboard.TargetName="ButtonBackground"> 41 <DiscreteObjectKeyFrame KeyTime="0" Value="Transparent"/> 42 </ObjectAnimationUsingKeyFrames> 43 </Storyboard> 44 </VisualState> 45 </VisualStateGroup> 46 <VisualStateGroup x:Name="PressedStatus"> 47 <VisualState x:Name="HasNotBeenPressed"/> 48 <VisualState x:Name="HasBeenPressed"> 49 <Storyboard> 50 <ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" Storyboard.TargetName="ellipse"> 51 <DiscreteObjectKeyFrame KeyTime="0"> 52 <DiscreteObjectKeyFrame.Value> 53 <Visibility>Visible</Visibility> 54 </DiscreteObjectKeyFrame.Value> 55 </DiscreteObjectKeyFrame> 56 </ObjectAnimationUsingKeyFrames> 57 </Storyboard> 58 </VisualState> 59 </VisualStateGroup> 60 </VisualStateManager.VisualStateGroups> 61 <Border x:Name="ButtonBackground" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" CornerRadius="0" Margin="{StaticResource PhoneTouchTargetOverhang}"> 62 <ContentControl x:Name="ContentContainer" ContentTemplate="{TemplateBinding ContentTemplate}" Content="{TemplateBinding Content}" Foreground="{TemplateBinding Foreground}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" Padding="{TemplateBinding Padding}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"/> 63 </Border> 64 <Ellipse x:Name="ellipse" Fill="Blue" HorizontalAlignment="Right" Margin="0,20,20,0" Stroke="Blue" Width="10" Height="10" VerticalAlignment="Top" Visibility="Collapsed"/> 65 </Grid> 66 </ControlTemplate> 67 </Setter.Value> 68 </Setter> 69 </Style> 70 </Application.Resources>
MainPage.xaml
1 <phone:PhoneApplicationPage 2 x:Class="PhoneApp1.MainPage" 3 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 4 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 5 xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone" 6 xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone" 7 xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 8 xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 9 mc:Ignorable="d" d:DesignWidth="480" d:DesignHeight="768" 10 FontFamily="{StaticResource PhoneFontFamilyNormal}" 11 FontSize="{StaticResource PhoneFontSizeNormal}" 12 Foreground="{StaticResource PhoneForegroundBrush}" 13 SupportedOrientations="Portrait" Orientation="Portrait" 14 shell:SystemTray.IsVisible="True"> 15 16 <!--LayoutRoot is the root grid where all page content is placed--> 17 <Grid x:Name="LayoutRoot" Background="Transparent"> 18 <Grid.RowDefinitions> 19 <RowDefinition Height="Auto"/> 20 <RowDefinition Height="*"/> 21 </Grid.RowDefinitions> 22 23 <!--TitlePanel contains the name of the application and page title--> 24 <StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28"> 25 <TextBlock x:Name="ApplicationTitle" Text="Blend Pro" Style="{StaticResource PhoneTextNormalStyle}"/> 26 <TextBlock x:Name="PageTitle" Text="Blend Pro" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/> 27 </StackPanel> 28 29 <!--ContentPanel - place additional content here--> 30 <Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0"> 31 <Button Content="Button" Height="72" Click="CustButton_Click" Tag="HasNotBeenPressed" Name="CustButton" Width="160" Style="{StaticResource CustomState}" /> 32 </Grid> 33 </Grid> 34 35 </phone:PhoneApplicationPage>
MainPage.xaml.cs
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Net; 5 using System.Windows; 6 using System.Windows.Controls; 7 using System.Windows.Documents; 8 using System.Windows.Input; 9 using System.Windows.Media; 10 using System.Windows.Media.Animation; 11 using System.Windows.Shapes; 12 using Microsoft.Phone.Controls; 13 14 namespace PhoneApp1 15 { 16 public partial class MainPage : PhoneApplicationPage 17 { 18 // Constructor 19 public MainPage() 20 { 21 InitializeComponent(); 22 } 23 24 private void CustButton_Click(object sender, RoutedEventArgs e) 25 { 26 if (CustButton.Tag.ToString() == "HasNotBeenPressed") 27 { 28 VisualStateManager.GoToState(CustButton, "HasBeenPressed", true); 29 CustButton.Tag = "HasBeenPressed"; 30 } 31 else 32 { 33 VisualStateManager.GoToState(CustButton, "HasNotBeenPressed", true); 34 CustButton.Tag = "HasNotBeenPressed"; 35 } 36 } 37 } 38 }