Windows phone自定义控件(无外观控件)——FlipPanel_移动开发_编程开发_程序员俱乐部

中国优秀的程序员网站程序员频道CXYCLUB技术地图
热搜:
更多>>
 
您所在的位置: 程序员俱乐部 > 编程开发 > 移动开发 > Windows phone自定义控件(无外观控件)——FlipPanel

Windows phone自定义控件(无外观控件)——FlipPanel

 2014/11/3 17:23:54  Monte  程序员俱乐部  我要评论(0)
  • 摘要:编码前无外观自定义控件的定义在上一篇中已经有了,至于这一篇的自定义控件,比之前多加入了状态的变化,就像默认的Button具有Pressed、Normal等状态。在状态转变的同时可以加上一些动画,可以让控件看起来更自然。FlipPanel控件的功能介绍:它具有两个状态,Normal和Flipped。当Normal状态时,控件显示正面的内容;当为Flipped状态时,控件显示反面的内容。除此之外,控件还有一个按钮,用来两个状态的跳转,并且也会随着状态的变化而有显示上的不同。编码
  • 标签:Windows 控件 自定义控件 自定义

编码

  无外观自定义控件的定义在上一篇中已经有了,至于这一篇的自定义控件,比之前多加入了状态的变化,就像默认的Button具有Pressed、Normal等状态。在状态转变的同时可以加上一些动画,可以让控件看起来更自然。

  FlipPanel控件的功能介绍:它具有两个状态,Normal和Flipped。当Normal状态时,控件显示正面的内容;当为Flipped状态时,控件显示反面的内容。除此之外,控件还有一个按钮,用来两个状态的跳转,并且也会随着状态的变化而有显示上的不同。

 

编码:

  1. 自定义一个继承于Control的FlipPanel的类,像上一篇类似,在构造函数中指示将使用它的默认样式:
    public class FlipPanel :Control
        {
            public FlipPanel()
            {
                DefaultStyleKey = typeof (FlipPanel);
            }
            。。。。。。
        }
  2. 根据需要定义一组依赖属性以及公开的属性封装器:
    <1>用来显示控件当前状态的属性:IsFlipped
    <2>正、方面的内容的属性:FrontContent、BackContent
    <3>在内容显示的时候设置边框光滑度的属性:CornerRadius

    public static readonly DependencyProperty IsFlipedProperty = DependencyProperty.Register(
                "IsFliped", typeof (bool), typeof (FlipPanel), new PropertyMetadata(default(bool)));
    
            public bool IsFliped
            {
                get { return (bool) GetValue(IsFlipedProperty); }
                set { SetValue(IsFlipedProperty, value); }
            }
    
            public static readonly DependencyProperty FrontContentProperty = DependencyProperty.Register(
                "FrontContent", typeof (object), typeof (FlipPanel), new PropertyMetadata(default(object)));
    
            public object FrontContent
            {
                get { return (object) GetValue(FrontContentProperty); }
                set { SetValue(FrontContentProperty, value); }
            }
    
            public static readonly DependencyProperty BackContentProperty = DependencyProperty.Register(
                "BackContent", typeof (object), typeof (FlipPanel), new PropertyMetadata(default(object)));
    
            public object BackContent
            {
                get { return (object) GetValue(BackContentProperty); }
                set { SetValue(BackContentProperty, value); }
            }
    
            public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
                "CornerRadius", typeof (CornerRadius), typeof (FlipPanel), new PropertyMetadata(default(CornerRadius)));
    
            public CornerRadius CornerRadius
            {
                get { return (CornerRadius) GetValue(CornerRadiusProperty); }
                set { SetValue(CornerRadiusProperty, value); }
            }
  3. 同上一篇的方法类似,在Themes/Generic.xaml中来定义自定义控件的默认样式:
    <Style TargetType="local:FlipPanel">
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:FlipPanel">
                        <Grid>
                            <Grid.RowDefinitions>
                                <RowDefinition Height="Auto"/>
                                <RowDefinition Height="Auto"/>
                            </Grid.RowDefinitions>
                            <!--This is the front content.-->
                            <Border x:Name="FrontContent" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" CornerRadius="{TemplateBinding CornerRadius}"
                                    Background="{TemplateBinding Background}">
                                <ContentPresenter Content="{TemplateBinding FrontContent}"/>
                            </Border>
                            <!--This is the back content.-->
                            <Border x:Name="BackContent" Opacity="0" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}"
                                    CornerRadius="{TemplateBinding CornerRadius}">
                                <ContentPresenter Content="{TemplateBinding BackContent}"/>
                            </Border>
                            <!--This is the flip button.-->
                            <ToggleButton Grid.Row="1" x:Name="FlipButton" RenderTransformOrigin="0.5,0.5" Margin="0,10,0,0" Height="30" Width="30">
                                <ToggleButton.Template>
                                    <ControlTemplate>
                                        <Grid>
                                            <Ellipse Stroke="Red" Fill="DarkGray"/>
                                            <Path Data="M1,1.5 L4.5,5 8,1.5" Stroke="Red" HorizontalAlignment="Center" VerticalAlignment="Center" StrokeThickness="2"/>
                                        </Grid>
                                    </ControlTemplate>
                                </ToggleButton.Template>
                                <ToggleButton.RenderTransform>
                                    <RotateTransform x:Name="FlipButtonTransform" Angle="-90" />
                                </ToggleButton.RenderTransform>
                            </ToggleButton>
                            
                            <VisualStateManager.VisualStateGroups>
                                <VisualStateGroup x:Name="ViewStates">
                                    <VisualState x:Name="Normal">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetName="BackContent" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:1"/>
                                            <DoubleAnimation Storyboard.TargetName="FrontContent" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:1"/>
                                            <DoubleAnimation Storyboard.TargetName="FlipButtonTransform" Storyboard.TargetProperty="Angle" To="-90" Duration="0:0:1"/>
                                        </Storyboard>
                                    </VisualState>
                                    <VisualState x:Name="Flipped">
                                        <Storyboard>
                                            <DoubleAnimation Storyboard.TargetName="BackContent" Storyboard.TargetProperty="Opacity" To="1" Duration="0:0:1"/>
                                            <DoubleAnimation Storyboard.TargetName="FlipButtonTransform" Storyboard.TargetProperty="Angle" To="90" Duration="0:0:1"/>
                                            <DoubleAnimation Storyboard.TargetName="FrontContent" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:1"/>
                                        </Storyboard>
                                    </VisualState>
                                </VisualStateGroup>
                            </VisualStateManager.VisualStateGroups>
                        </Grid>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>

          1.上面的XAML与之前的定义控件外观差不多,有两个Border,一个ToggleButton组成。其中Border中显示的ContentPresenter中的内容绑定到了控件中内容的属性上,及FrontContent和BackContent。并且多了一个关于状态的设置。
          2.这里如同上面介绍的,控件具有两个状态,这两个状态属于对立的状态(及同时只能处在其中一个状态中),他们是在一个名为ViewStates的状态分组中。
          3.在转化到不同状态时,使用了动画,用来让转化过程平滑一点。
          4.建议为FlipPanel控件类应用TemplatePart特性,包括可视化状态TemplateVisualState:

     [TemplatePart(Name = "FlipButton",Type = typeof(ToggleButton)),
      TemplateVisualState(Name = "Normal",GroupName = "ViewStates"),
      TemplateVisualState(Name = "Flipped",GroupName = "VisualStates")]

     

  4. 模板中的那个ToggleButton按钮用来转换状态,所以对于它,应该处理它的点击事件。依旧是在重写的OnApplyTemplate函数中来获取控件,并注册它的Click事件。
     1         public override void OnApplyTemplate()
     2         {
     3             base.OnApplyTemplate();
     4             ToggleButton flipButton = GetTemplateChild("FlipButton") as ToggleButton;
     5             if(flipButton!=null)
     6                 flipButton.Click += flipButton_Click;
     7         }
     8 
     9        void flipButton_Click(object sender, RoutedEventArgs e)
    10         {
    11             this.IsFliped = !this.IsFliped;
    12         }

    此刻点击FlipButton按钮就可以改变控件的状态了,也就是IsFlipped的值。

  5. 现在状态是有了(写在XAML中),单击FlipButton按钮也会改变控件的状态值。但是我们怎样让IsFipped的状态值关联到样式模板中的状态呢?答案是使用VisualStateManager类来控制状态的转变,用的的是他的其中的函数GotoState。
    1         private void OnChangedState(bool useTransitions)
    2         {
    3             if (IsFliped)
    4                 VisualStateManager.GoToState(this, "Flipped", useTransitions);
    5             else
    6                 VisualStateManager.GoToState(this, "Normal", useTransitions);
    7         }

        GoToState中第一个参数为发生状态变化的控件,第二个参数就是控件所要到达的状态,第三个参数是否使用状态过渡
    并且在OnApplyTemplate函数和flipButton_Click函数中进行调用

     1         public override void OnApplyTemplate()
     2         {
     3             base.OnApplyTemplate();
     4             ToggleButton flipButton = GetTemplateChild("FlipButton") as ToggleButton;
     5             if(flipButton!=null)
     6                 flipButton.Click += flipButton_Click;
     7             OnChangedState(false);
     8         }
     9 
    10         void flipButton_Click(object sender, RoutedEventArgs e)
    11         {
    12             this.IsFliped = !this.IsFliped;
    13             OnChangedState(true);
    14         }

     

  6. 简单的带状态的自定义控件已经定义好了,之后就可以直接使用了。例:
    <control:FlipPanel  BorderBrush="PowderBlue" BorderThickness="2" CornerRadius="10" Margin="12">
                        <control:FlipPanel.FrontContent>
                            <StackPanel Margin="6">
                                <Button Background="Purple" Margin="3" Content="FrontContent1"/>
                                <Button Background="Red" Margin="3" Content="FrontContent2"/>
                                <Button Background="Blue" Margin="3" Content="FrontContent3"/>
                                <Button Background="GreenYellow" Margin="3" Content="FrontContent4"/>
                            </StackPanel>
                        </control:FlipPanel.FrontContent>
                        <control:FlipPanel.BackContent>
                            <Grid Margin="12">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="Auto"/>
                                    <RowDefinition/>
                                </Grid.RowDefinitions>
                                <TextBlock  FontSize="20" Margin="3" HorizontalAlignment="Center" Foreground="Peru">This is the FlipPanel's back.</TextBlock>
                                <Button Grid.Row="2" Margin="3" Content="Back" HorizontalAlignment="Center" VerticalAlignment="Center"/>
                            </Grid>
                        </control:FlipPanel.BackContent>
                    </control:FlipPanel>

    Normal状态下截图为

    当点击下方的按钮以后,控件状态变为Flipped:



编码后

  1. 当然你可以使用Style在使用的时候自定义一个样式,从而改变他的默认样式,达到自己想要的布局。
  2. 自定义无外观的控件时,最重要的是想着,要这个控件实现什么样的功能和逻辑。并抽出功能和逻辑中会使用到的控件作为模板部件,以便让控件使用者重写样式方便的同时不会丢掉控件的功能。
  3. 设计好样式的同时,要根据需要来设计控件不同状态之间的转换,可以通过动画来进行状态转换时的效果以及处于状态中时,控件的显示效果。
发表评论
用户名: 匿名