编码前

  无外观自定义控件的定义在上一篇中已经有了,至于这一篇的自定义控件,比之前多加入了状态的变化,就像默认的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事件。
             public override void OnApplyTemplate()
    {
    base.OnApplyTemplate();
    ToggleButton flipButton = GetTemplateChild("FlipButton") as ToggleButton;
    if(flipButton!=null)
    flipButton.Click += flipButton_Click;
    } void flipButton_Click(object sender, RoutedEventArgs e)
    {
    this.IsFliped = !this.IsFliped;
    }

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

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

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

             public override void OnApplyTemplate()
    {
    base.OnApplyTemplate();
    ToggleButton flipButton = GetTemplateChild("FlipButton") as ToggleButton;
    if(flipButton!=null)
    flipButton.Click += flipButton_Click;
    OnChangedState(false);
    } void flipButton_Click(object sender, RoutedEventArgs e)
    {
    this.IsFliped = !this.IsFliped;
    OnChangedState(true);
    }
  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. 设计好样式的同时,要根据需要来设计控件不同状态之间的转换,可以通过动画来进行状态转换时的效果以及处于状态中时,控件的显示效果。

Windows phone自定义控件(无外观控件)——FlipPanel的更多相关文章

  1. Windows phone 自定义控件(无外观控件)——ColorPicker

    编码前 在上一篇博客中,写的是一个UserControl的子类,它具有固定的外观(虽然也可以通过样式来进行修改,但受到的限制很大).如果你想要使用这个控件的逻辑,但是希望在使用的时候可以更改控件的外观 ...

  2. WPF教程十二:了解自定义控件的基础和自定义无外观控件

    这一篇本来想先写风格主题,主题切换.自定义配套的样式.但是最近加班.搬家.新租的房子打扫卫生,我家宝宝6月中旬要出生协调各种的事情,导致了最近精神状态不是很好,又没有看到我比较喜欢的主题风格去模仿的, ...

  3. 【WPF学习】第六十五章 创建无外观控件

    用户控件的目标是提供增补控件模板的设计表面,提供一种定义控件的快速方法,代价是失去了将来的灵活性.如果喜欢用户控件的功能,但需要修改使其可视化外观,使用这种方法就有问题了.例如,设想希望使用相同的颜色 ...

  4. 背水一战 Windows 10 (79) - 自定义控件: Layout 系统, 控件模板, 事件处理

    [源码下载] 背水一战 Windows 10 (79) - 自定义控件: Layout 系统, 控件模板, 事件处理 作者:webabcd 介绍背水一战 Windows 10 之 控件(自定义控件) ...

  5. C# 自定义控件VS用户控件

    1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Container控件可以添加其他Con ...

  6. 《深入理解Windows Phone 8.1 UI控件编程》基于最新的Runtime框架

    <深入理解Windows Phone 8.1 UI控件编程>本书基于最新的Windows Phone 8.1 Runtime SDK编写,全面深入地论述了最酷的UI编程技术:实现复杂炫酷的 ...

  7. 重新想象 Windows 8 Store Apps (15) - 控件 UI: 字体继承, Style, ControlTemplate, SystemResource, VisualState, VisualStateManager

    原文:重新想象 Windows 8 Store Apps (15) - 控件 UI: 字体继承, Style, ControlTemplate, SystemResource, VisualState ...

  8. 重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试

    原文:重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试 [源码下载] 重新想象 Windows 8 Store ...

  9. 重新想象 Windows 8 Store Apps (3) - 控件之内容控件: ToolTip, Frame, AppBar, ContentControl, ContentPresenter; 容器控件: Border, Viewbox, Popup

    原文:重新想象 Windows 8 Store Apps (3) - 控件之内容控件: ToolTip, Frame, AppBar, ContentControl, ContentPresenter ...

随机推荐

  1. poj 3255 Roadblocks 次短路(两次dijksta)

    Roadblocks Time Limit : 4000/2000ms (Java/Other)   Memory Limit : 131072/65536K (Java/Other) Total S ...

  2. Bootstrap:百科

    ylbtech-Bootstrap:百科 Bootstrap (Web框架) Bootstrap,来自 Twitter,是目前很受欢迎的前端框架.Bootstrap 是基于 HTML.CSS.Java ...

  3. shell_sctipts: 删除mysql备份到最后7日

    目前,mysql的备份文件,经过一周左右清理,手动清理会比较费事,所以写了一个简单脚本来实现. 前提介绍: mysql备份文件放在/usr/bak/sql里面,sql文件的备份名称格式为: mysql ...

  4. Linux 简单命令查询CPU、内存、网卡等信息

    [转自]Linux查询CPU.内存.网卡等信息 看CPU信息(型号)# cat /proc/cpuinfo | grep name | cut -f2 -d: |uniq -c      1  Int ...

  5. Linux下XAMPP装完之后,Navicat无法连上数据库的问题的解决 注意'mypassword'是当前的mysql登录密码

    Linux下装完XAMPP之后,mysql是自带装好了的,这个时候,mysql的root用户没有密码. 在mac 下安装好xampp后,需要在终端命令行操作时,比如输入:mysql -u root - ...

  6. vmware12共享windows的文件给虚拟的linux

    1:首先我的vmware的版本是12的 点击vmware的虚拟机---------------------->设置------------------------>选项---------- ...

  7. 查看虚拟机CENTOS7 的 IP 地址和命令

    用于生产环境下  安装CENTOS7 太费时间, 研究阶段 放在虚拟机里面  是最好的选择: 但是安装完毕后 就出现问题    无法使用IFCONFIG : 毕竟 内核不一样 首先我们登录操作系统 用 ...

  8. centos6.5 64安装ffmpeg过程支持转码mp3

    百度了几个文章 大致知道了思路 首先yum源安装是木有的,只能编译安装了. 要安装ffmpeg要先安装一个yasm支持汇编优化(FFmpeg需要) 在安装一个lame,支持mp3的转码 那就是需要3步 ...

  9. ASP.Net在web.config中设置上传文件的大小方法

    修改Webcong文件:<system.web><httpRuntime maxRequestLength="40960"   //即40MB,1KB=1024u ...

  10. 字符串和JSON对象互转的方法

    采用Ajax的项目开发过程中,经常需要将JSON格式的字符串返回到前端,前端解析成JS对象(JSON ).字符串转JSON对象 1.eval方式解析.function strToJson(str){ ...