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 ...
随机推荐
- LINK : fatal error LNK1158: 无法运行“rc.exe”解决办法 and Visual Studio 2017 下载安装
LINK : fatal error LNK1158: 无法运行“rc.exe” 首先下载软件包:https://pan.baidu.com/s/1L1N1sikXUaZZd-9nmZnwjA 第一个 ...
- 关于String.valueOf()和.toString的问题
以下是String.valueOf()的源代码 public static String valueOf(Object obj) { return (obj == null) ? " ...
- CSS 标签实例二
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- 在Linux 系统 Latex安装 使用入门教程
来源: http://blog.chinaunix.net/u/25605/showart_2100398.html 入门介绍好文:TeX.LaTeX.TeXLive 小结 笔记详情:http://v ...
- Windows 8的用户模式Shim Engine小探及利用
转载: https://bbs.pediy.com/thread-175483.htm Windows Shim Engine,即Windows 兼容性模式实现引擎,在exe文件的属性对话框中有一个兼 ...
- python + docker, 实现天气数据 从FTP获取以及持久化(五)-- 利用 Docker 容器化 Python 程序
背景 不知不觉中,我们已经完成了所有的编程工作.接下来,我们需要把 Python 程序 做 容器化 (Docker)部署. 思考 考虑到项目的实际情况,“持久化天气”的功能将会是一个独立的功能模块发布 ...
- MiniDump产生工具
1:分析程序异常等等信息,在入口处初始化即可 //生成Dump文件信息 OS:Windows #pragma once #include <windows.h> #include < ...
- storm的可靠性
消息确认机制: 在数据发送的过程中可能会数据丢失导致没能接收到,spout有个超时时间(默认是30S),如果30S过去了还是没有接收到数据,也认为是处理失败. 运行结果都是处理成功 参考代码Storm ...
- diskspd的使用
参数翻译 可测试目标: file_path 文件abc.file #<physical drive number> #1为第一块物理磁盘[谨慎,别拿系统盘测试,一般用于准备投入的数据磁盘测 ...
- Xshell批量导入IP地址
我的xshell被覆盖了~~~结果原来的host没了,很郁闷要一个一个添加,网上找了很长时间在Xshell中批量添加IP的文章,结果都不行. 最后找到了https://blog.netsarang.c ...