Windows phone自定义控件(无外观控件)——FlipPanel
编码前
无外观自定义控件的定义在上一篇中已经有了,至于这一篇的自定义控件,比之前多加入了状态的变化,就像默认的Button具有Pressed、Normal等状态。在状态转变的同时可以加上一些动画,可以让控件看起来更自然。
FlipPanel控件的功能介绍:它具有两个状态,Normal和Flipped。当Normal状态时,控件显示正面的内容;当为Flipped状态时,控件显示反面的内容。除此之外,控件还有一个按钮,用来两个状态的跳转,并且也会随着状态的变化而有显示上的不同。
编码:
- 自定义一个继承于Control的FlipPanel的类,像上一篇类似,在构造函数中指示将使用它的默认样式:
public class FlipPanel :Control
{
public FlipPanel()
{
DefaultStyleKey = typeof (FlipPanel);
}
。。。。。。
} - 根据需要定义一组依赖属性以及公开的属性封装器:
<1>用来显示控件当前状态的属性:IsFlipped
<2>正、方面的内容的属性:FrontContent、BackContent
<3>在内容显示的时候设置边框光滑度的属性:CornerRadiuspublic 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); }
} - 同上一篇的方法类似,在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")] - 模板中的那个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的值。
- 现在状态是有了(写在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);
} - 简单的带状态的自定义控件已经定义好了,之后就可以直接使用了。例:
<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:

编码后
- 当然你可以使用Style在使用的时候自定义一个样式,从而改变他的默认样式,达到自己想要的布局。
- 自定义无外观的控件时,最重要的是想着,要这个控件实现什么样的功能和逻辑。并抽出功能和逻辑中会使用到的控件作为模板部件,以便让控件使用者重写样式方便的同时不会丢掉控件的功能。
- 设计好样式的同时,要根据需要来设计控件不同状态之间的转换,可以通过动画来进行状态转换时的效果以及处于状态中时,控件的显示效果。
Windows phone自定义控件(无外观控件)——FlipPanel的更多相关文章
- Windows phone 自定义控件(无外观控件)——ColorPicker
编码前 在上一篇博客中,写的是一个UserControl的子类,它具有固定的外观(虽然也可以通过样式来进行修改,但受到的限制很大).如果你想要使用这个控件的逻辑,但是希望在使用的时候可以更改控件的外观 ...
- WPF教程十二:了解自定义控件的基础和自定义无外观控件
这一篇本来想先写风格主题,主题切换.自定义配套的样式.但是最近加班.搬家.新租的房子打扫卫生,我家宝宝6月中旬要出生协调各种的事情,导致了最近精神状态不是很好,又没有看到我比较喜欢的主题风格去模仿的, ...
- 【WPF学习】第六十五章 创建无外观控件
用户控件的目标是提供增补控件模板的设计表面,提供一种定义控件的快速方法,代价是失去了将来的灵活性.如果喜欢用户控件的功能,但需要修改使其可视化外观,使用这种方法就有问题了.例如,设想希望使用相同的颜色 ...
- 背水一战 Windows 10 (79) - 自定义控件: Layout 系统, 控件模板, 事件处理
[源码下载] 背水一战 Windows 10 (79) - 自定义控件: Layout 系统, 控件模板, 事件处理 作者:webabcd 介绍背水一战 Windows 10 之 控件(自定义控件) ...
- C# 自定义控件VS用户控件
1 自定义控件与用户控件区别 WinForm中, 用户控件(User Control):继承自 UserControl,主要用于开发 Container 控件,Container控件可以添加其他Con ...
- 《深入理解Windows Phone 8.1 UI控件编程》基于最新的Runtime框架
<深入理解Windows Phone 8.1 UI控件编程>本书基于最新的Windows Phone 8.1 Runtime SDK编写,全面深入地论述了最酷的UI编程技术:实现复杂炫酷的 ...
- 重新想象 Windows 8 Store Apps (15) - 控件 UI: 字体继承, Style, ControlTemplate, SystemResource, VisualState, VisualStateManager
原文:重新想象 Windows 8 Store Apps (15) - 控件 UI: 字体继承, Style, ControlTemplate, SystemResource, VisualState ...
- 重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试
原文:重新想象 Windows 8 Store Apps (16) - 控件基础: 依赖属性, 附加属性, 控件的继承关系, 路由事件和命中测试 [源码下载] 重新想象 Windows 8 Store ...
- 重新想象 Windows 8 Store Apps (3) - 控件之内容控件: ToolTip, Frame, AppBar, ContentControl, ContentPresenter; 容器控件: Border, Viewbox, Popup
原文:重新想象 Windows 8 Store Apps (3) - 控件之内容控件: ToolTip, Frame, AppBar, ContentControl, ContentPresenter ...
随机推荐
- javascript的事件流
事件流包括三个阶段: 1.事件捕获阶段 2.处于目标阶段 3.事件冒泡阶段 1.事件捕获阶段 现在页面中有一个按钮. 如果单击这个按钮的话,在事件捕获过程中,document会首先接收到click事件 ...
- Spring MVC 原生API
原生API: Servlet环境中一些有用的对象: HttpServletRequest HttpServletResponse HttpSession Reader Writer InputStre ...
- kudu和kudu-impala的安装流程
安装apache的kudu 第一步:下载rpm包 http://archive.cloudera.com/kudu/redhat/6/x86_64/kudu/5.11.0/RPMS/x86_64/ 第 ...
- Sublime Text 3 个人使用总结
待更新 Sublime Text 3\Packages\FileHeader\template\header
- QQ去除聊天框广告详解——2016.9 版
QQ聊天框广告很烦人,百度出来的一些方法早已过时,下面是博主整理出来的方法,供各位同学参考. 1.按键盘上的 Win+R 快捷键打开运行框,然后复制并粘贴 Application Data\Tence ...
- selenium+python自动化87-Chrome浏览器静默模式启动(headless)
前言 selenium+phantomjs可以打开无界面的浏览器,实现静默模式启动浏览器完成自动化测试,这个模式是极好的,不需要占用电脑的屏幕. 但是呢,phantomjs这个坑还是比较多的,并且遇到 ...
- linnux-shell知识
awk 是单行处理文本 正则: cat test.py | awk '/a/ {print $1}' # 如果test.py中存在a这个字母,就打印所在行的第一列(注意是该列,不是该词).匹配成功, ...
- CentOS7.3下yum练手安装Nginx,支持php5.4
yum install php php-devel 安装的是5.4 那么安装完毕了,怎么设置nginx和php 解析 1 添加nginx 默认主页index.php vim .../etc/ngin ...
- Springboot spring data jpa 多数据源的配置01
Springboot spring data jpa 多数据源的配置 (说明:这只是引入了多个数据源,他们各自管理各自的事务,并没有实现统一的事务控制) 例: user数据库 global 数据库 ...
- localhost 127.0.0.1
No1: localhost也叫local ,正确的解释是:本地服务器 127.0.0.1在windows等系统的正确解释是:本机地址(本机服务器) 他们的解析通过本机的host文件,windows自 ...