zoukankan      html  css  js  c++  java
  • Windows phone自定义控件(无外观控件)——FlipPanel

    编码前

      无外观自定义控件的定义在上一篇中已经有了,至于这一篇的自定义控件,比之前多加入了状态的变化,就像默认的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. 设计好样式的同时,要根据需要来设计控件不同状态之间的转换,可以通过动画来进行状态转换时的效果以及处于状态中时,控件的显示效果。
  • 相关阅读:
    GridView取不到值的问题总结
    DataGridView中的Combobox的应用
    .NET开发的一些积累
    .net字符串内存的分配
    冒泡排序
    字段自动递增的数据库建表的SQL写法
    [数据库]简单SQL语句总结
    C#知识
    sql语句大全
    白盒测试和黑盒测试
  • 原文地址:https://www.cnblogs.com/Monte/p/4071460.html
Copyright © 2011-2022 走看看