好玩的WPF第一弹:窗口抖动+边框阴影效果+倒计时显示文字
大家一进到博客就应该看到这张GIF了吧……好吧,今天不是星期一……
那么就来一起做做这个效果啦!看完记得点赞哦~
新建一个WPF项目
如果新建WPF项目应该不用我说了吧,在C#下面找找就好了。
MainWindow.xaml
在初始的Window下添加如下属性:
x:Name="mainWindow"
WindowStartupLocation="CenterScreen"
WindowState="Normal"
WindowStyle="None"
AllowsTransparency="True"
Loaded="Window_Loaded"
Background="Green"
ResizeMode="NoResize"
分别是什么意思呢?
1、给窗口命名,以后后面会用到的。
2、设置窗口的出现位置,这里设置为屏幕中心,你可以设置其他位置。
3、窗口的大小,我设置为正常,你也可以设置为全屏(Maximized)。
4、窗口的样式,此处设为无标题。
5、窗口的边框,True表示无边框。
6、窗口的加载事件,稍后会补充的。
7、背景颜色,你可以再修改。
8、不可改变窗口尺寸。
然后被预设好的Grid添加一个名字:
<Grid x:Name="mainGrid">
</Grid>
那么界面部分就设好咯。
MainWindow.xaml.cs
你首先需要一个计时器:
// 创建DispatcherTimerr对象
private DispatcherTimer dTimer = null;
还需要一个前面提到的Window_Loaded事件:
// 窗体加载事件
private void Window_Loaded(object sender, RoutedEventArgs e)
{dTimer = new DispatcherTimer();// 时间间隔,比如每两秒刷新一次dTimer.Interval = TimeSpan.FromSeconds(1); dTimer.Tick += new EventHandler(timer_Tick);dTimer.Start();
}
我们现在应该来写timer_Tick事件了,不过在此之前我们应该决定将要显示什么内容。就以“今天星期一”好了,我们可以创建一个数组,用一个整型变量作为计数器。
我接下来可能比较啰嗦,但只是因为想必看我博客的大多是学生,希望能稍微教教大家思考的方式。
在MainWindow函数前定义全局变量如下:
private int count = 5;
private string[] txt = new string[5] {"今","天","星","期","一"};
计时器方法如下:
private void timer_Tick(object sender,EventArgs e)
{if (count == 0){dTimer.Stop();count = 5;dTimer.Start();}else{TextWindow textWindow = new TextWindow(this.mainGrid,this.mainWindow);textWindow.TxtValue = txt[count-1].ToString();textWindow.HorizontalAlignment = System.Windows.HorizontalAlignment.Center;textWindow.VerticalAlignment = System.Windows.VerticalAlignment.Center;this.mainGrid.Children.Add(textWindow);count--;}
}
如果计数器已经为0了,说明数组内的内容已经全部都显示了一遍,那么将其重置后再次开启计数器。
如果不为0,先实例化一个TextWindow窗口,至于这个窗口是做什么的,我们稍后再看。
再随后我们将数组内的字符串赋值给TextWindow类的实例的属性,并设置它的显示位置。
然后将TextWindow窗口添加到mainGrid中,最后将计数器减一。
TextWindow.xaml
新建一个XAML页面大家也会的吧?当然,也可以直接创建UserControl页面。
添加如下代码(我会逐个说明的):
<UserControl x:Class="WpfApplication1.TextWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" RenderTransformOrigin="0.5,0.5" Loaded="UserControl_Loaded"mc:Ignorable="d"><UserControl.RenderTransform><TransformGroup><ScaleTransform x:Name="scale" /></TransformGroup> </UserControl.RenderTransform> <TextBlock x:Name="textBlock" Width="200" Height="200"FontSize="180" TextAlignment="Center" FontWeight="Bold" FontFamily="宋体" Foreground="Wheat"/></UserControl>
1、RenderTransformOrigin的作用,通俗的讲,就是文字即将从哪个角度出来。此处是窗口的中心。
<1,0>是左下角;<0,1>是右上角
<1,1>是左上角;<0.0>是右下角
2、Loaded同样和前面是一样是加载事件
3、TransformGroup,我们稍后会见到
4、TextBlock用来显示文本
TextWindow.xaml.cs
在类TextWindow中设置以下变量,我们前面也看到了,会从MainWindow中传入相关参数:
private Grid grid = null;
private Window window=null;
因为窗口会有抖动效果,所以呢,就需要两个参数来定位它:
//记录初始位置
private double left = 0;
private double top = 0;
Storyboard以前我都是用Blend写的,这里直接刷代码有点难度。
// 创建动画
private Storyboard storyboard = null;
记得设置一个属性来传递文本参数。
// 给UserControl中的文本框赋值
private string txtValue = string.Empty;
public string TxtValue
{get { return txtValue; }set { txtValue = value; this.textBlock.Text = txtValue; }
}
如前所述,是时候传递这两个参数了:
public TextWindow(Grid _grid, Window _window)
{InitializeComponent();grid = _grid;window = _window;left = window.Left;top = window.Top;
}
接下来就是这个项目里最重大的过程了,难度也很大,每一个参数都得多次尝试才好。
先写方法:
private void UserControl_Loaded(object sender, RoutedEventArgs e)
方法内定义动画:
// 创建动画对象实例
storyboard = new Storyboard();
文字的缩放过程:
// ScaleX缩放过程DoubleAnimation doubleAnimationX = new DoubleAnimation();
doubleAnimationX.Duration = TimeSpan.FromSeconds(0.8);
// 此处将用于文字出现时的缩放
doubleAnimationX.From = 20;
doubleAnimationX.To = 1;
Storyboard.SetTarget(doubleAnimationX, this);
Storyboard.SetTargetProperty(doubleAnimationX, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleX)"));// ScaleY缩放过程
DoubleAnimation doubleAnimationY = new DoubleAnimation();
doubleAnimationY.Duration = TimeSpan.FromSeconds(0.8);
doubleAnimationY.From = 20;
doubleAnimationY.To = 1;
Storyboard.SetTarget(doubleAnimationY, this);
Storyboard.SetTargetProperty(doubleAnimationY, new PropertyPath("(UIElement.RenderTransform).(TransformGroup.Children)[0].(ScaleTransform.ScaleY)"));
试想一下,如果文字堂而皇之的冒了出来不太美观吧?如果有一个由大到小的缩放过程,那不是很赞么?
代码我觉得应该都能看懂,SetTargetProperty属性是在后台代码中设置属性的一个非常好的方式,大家如果会用“资源”,可以类比来思考一下。如果没用过资源也没关系,后面我们会见到。
前面是写的缩放部分,我们还可以添加一个透明度的过渡过程如下:
// Opacity变换动画
DoubleAnimation doubleAnimationO = new DoubleAnimation();
doubleAnimationO.Duration = TimeSpan.FromSeconds(0.8);
// 文字的透明度
doubleAnimationO.From = 0;
doubleAnimationO.To = 1;
Storyboard.SetTarget(doubleAnimationO, this);
Storyboard.SetTargetProperty(doubleAnimationO, new PropertyPath("(Opacity)"));
最终切记将这三个实例添加到storyboard中。
storyboard.Children.Add(doubleAnimationX);
storyboard.Children.Add(doubleAnimationY);
storyboard.Children.Add(doubleAnimationO);
窗口抖动效果如下:
// 窗口抖动效果DoubleAnimation doubleAnimationL1 = new DoubleAnimation();doubleAnimationL1.BeginTime = TimeSpan.FromSeconds(0.6);doubleAnimationL1.Duration = TimeSpan.FromSeconds(0.2);doubleAnimationL1.From = window.Left;doubleAnimationL1.To = window.Left - 12;doubleAnimationL1.EasingFunction = new BounceEase() { Bounces = 12, EasingMode = EasingMode.EaseInOut };Storyboard.SetTarget(doubleAnimationL1, window);Storyboard.SetTargetProperty(doubleAnimationL1, new PropertyPath("(Left)"));DoubleAnimation doubleAnimationL2 = new DoubleAnimation();doubleAnimationL2.BeginTime = TimeSpan.FromSeconds(0.7);doubleAnimationL2.Duration = TimeSpan.FromSeconds(0.2);doubleAnimationL2.From = window.Left;doubleAnimationL2.To = window.Left + 12;doubleAnimationL2.EasingFunction = new BounceEase() { Bounces = 12, EasingMode = EasingMode.EaseInOut };Storyboard.SetTarget(doubleAnimationL2, window);Storyboard.SetTargetProperty(doubleAnimationL2, new PropertyPath("(Left)")); DoubleAnimation doubleAnimationT1 = new DoubleAnimation();doubleAnimationT1.BeginTime = TimeSpan.FromSeconds(0.6);doubleAnimationT1.Duration = TimeSpan.FromSeconds(0.2);doubleAnimationT1.From = window.Top;doubleAnimationT1.To = window.Top + 12; ;doubleAnimationT1.EasingFunction = new BounceEase() { Bounces = 12, EasingMode = EasingMode.EaseInOut };Storyboard.SetTarget(doubleAnimationT1, window);Storyboard.SetTargetProperty(doubleAnimationT1, new PropertyPath("(Top)"));DoubleAnimation doubleAnimationT2 = new DoubleAnimation();doubleAnimationT2.BeginTime = TimeSpan.FromSeconds(0.7);doubleAnimationT2.Duration = TimeSpan.FromSeconds(0.2);doubleAnimationT2.From = window.Top;doubleAnimationT2.To = window.Top - 12;doubleAnimationT2.EasingFunction = new BounceEase() { Bounces = 12, EasingMode = EasingMode.EaseInOut };Storyboard.SetTarget(doubleAnimationT2, window);Storyboard.SetTargetProperty(doubleAnimationT2, new PropertyPath("(Top)"));
和上面的缩放和透明度一样,添加这些属性到storyboard中。
storyboard.Children.Add(doubleAnimationL1);
storyboard.Children.Add(doubleAnimationL2);
storyboard.Children.Add(doubleAnimationT1);
storyboard.Children.Add(doubleAnimationT2);
最后就是注册事件咯:
storyboard.Completed += new EventHandler(storyboard_Completed);
storyboard.Begin(this, true);
至此该方法就完成了,然后就开始新的storyboard_Completed方法了。
private void storyboard_Completed(object sender, EventArgs e)
{// 解除绑定 storyboard.Remove(this);// 解除TextWindow窗口 storyboard.Children.Clear();grid.Children.Clear();// 恢复窗体初始位置window.Left = left;window.Top = top;
}
这个方法所做的事情简单的说,就是在完成一个storyboard动画后接触所有绑定,刷新画面(不然上一次的文字不消失回和下一次显示的文字重叠),然后将窗口归位。
调试和解决问题
那么至此就来调试一下吧~
呀,文字的出现顺序反了哦……
想想问题出在这里呢:
private string[] txt = new string[5] {"今","天","星","期","一"};
textWindow.TxtValue = txt[count-1].ToString();
我们首先将数组最后一个打印出来了,然后依次第四个、第三个……
要么将打印顺序改变,要么定义数组的时候反向定义,但这两种方式都不人性化。比如说我们可能要让用户输入数组内容,总不好让用户反向输入吧?
所以我们中间插入一个方法,来讲数组逆序输出。
static string[] ReverseStringArray(string[] str){int length = str.Length;string[] newStr = new string[length];for (int i = 0; i < length; i++){newStr[i] = str[length - i - 1];}return newStr;}
然后在MainWindow函数中执行该方法:
txt= ReverseStringArray(txt);
调试一下果然奏效~
不过还有一种更加简单的方式,C#的自带方法:
Array.Reverse(txt);
还可能你会遇到这个问题:不就是“今天星期一”五个字嘛,至于让每个字弄成一个字符串然后组成数组嘛,直接上字符串不行?
当然可以:
private string txt = "今天星期一";
那么逆序的问题怎么解决?
static string ReverseString(string str){int length = str.Length;StringBuilder stringB = new StringBuilder(length);for (int i = length - 1; i >= 0; i--)stringB.Append(str[i]);return stringB.ToString();}
txt = ReverseString(txt);
字符串本身也是数组,只不过是由字符组成的。
如果读者是初学者的话,我也来证明一下吧。
还记得这个么?
textWindow.TxtValue = txt[count - 1].ToString();
最后无论是字符还是字符串我都调用了ToString()方法来转换成字符,但如果txt是字符串,而把.ToString()去掉的话就会报错了,因为它不是字符串。
好了,下面来给大家看看另一种取出字符串中字符的方法:
textWindow.TxtValue = txt.ElementAt(count - 1).ToString();
这个真的非常好用。
So……到此为止了,和开篇中的GIF效果一模一样了。
那么给大家留一个小练习,如果txt是一个字符串数组呢?
private string[] txt = new string[5] { "欢迎访问我的博客", "再次欢迎访问我的博客","觉得不错的话就点个赞呗", "你还可以在下面评论", "也可以给我发邮件" };
需要每次都打印出来一句话,而非一个字,该怎么做?
文章结尾我会给出思路,大家不妨在看下文前先试试。
App.xaml
好了,标题中的窗口抖动和倒计时显示文字都有了。那么边框呢?现在虽然是无边框了,但总感觉不那么精致,怎样让它有阴影效果呢?
那么,打开App.xaml,添加如下资源样式就好了。
<Style x:Key="window_style" TargetType="{x:Type Window}"><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type Window}"><Grid Margin="10"><Rectangle Fill="{DynamicResource {x:Static SystemColors.WindowBrushKey}}" RadiusX="5" RadiusY="5"><Rectangle.Effect><DropShadowEffect BlurRadius="10" ShadowDepth="0"/></Rectangle.Effect></Rectangle><Border Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Margin}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" CornerRadius="5"><ContentPresenter /></Border></Grid></ControlTemplate></Setter.Value></Setter></Style>
最后在MainWindow.xaml下的Window中添加该资源:
Style="{StaticResource window_style}"
那么最终的效果如下:
那么关于前面的小练习呢,其实解决的障碍在于,一个字符串的字数太多,原本的
TextBlock的200宽度已经不能满足了,于是乎,干脆删了它:
<TextBlock x:Name="textBlock" Height="200" FontSize="80" TextAlignment="Center" FontWeight="Bold" FontFamily="宋体" Foreground="Wheat"/>
当然了,字体也要调小一点。
可是这样并不完美,因为有这么多字,一秒钟的时间并不能看完吧。所以还得修改一下比较好,我将我修改过的地方贴出来……
doubleAnimationX.Duration = TimeSpan.FromSeconds(3);
doubleAnimationX.From = 15;doubleAnimationY.Duration = TimeSpan.FromSeconds(3);
doubleAnimationY.From = 15;doubleAnimationO.Duration = TimeSpan.FromSeconds(3);
dTimer.Interval = TimeSpan.FromSeconds(5);
好了,博客结束啦,我也写了好久。要源码的话就在评论里留邮箱吧……我一个一个发了……
感谢您的访问,希望对您有所帮助。 欢迎大家关注、收藏以及评论。
为使本文得到斧正和提问,转载请注明出处:
http://blog.csdn.net/nomasp
好玩的WPF第一弹:窗口抖动+边框阴影效果+倒计时显示文字相关推荐
- 好玩的WPF第二弹:电子表字体显示时间+多彩呼吸灯特效button
我们先来看看Quartz MS字体动态显示系统时间的效果,难度相较于上一篇也要简单很多. 首先是定义一个TextBlock例如以下. <Grid><TextBlock Name=&q ...
- [WPF疑难] 模式窗口被隐藏后重新显示时变成了非模式窗口
原文:[WPF疑难] 模式窗口被隐藏后重新显示时变成了非模式窗口 [WPF疑难] 模式窗口被隐藏后重新显示时变成了非模式窗口 周银辉 现象: 大家可以试试下面这个很有趣但会带来Defect的现象:当我 ...
- html给文字加黑色边框,如何给显示文字加一层黑色边框
在工作中遇到这样一个问题,在实时监视的视频显示中需要在视频中显示当前时间,通道名等额外信息,无论信息内容在视频画面上采用何种颜色显示,当信息显示区域背景的视频画面的颜色正好与显示信息内容的颜色一致或差 ...
- EXCEL多页打印时,上边框线无法显示
excel打印多页,从第二页开始第一行的上边框线无法显示.请问怎么解决. 不是不显示.是正好与上面的页眉的下面的显示重叠了.所以,看着不明显.但是打印预览是正常的. 调整下页面 打印预览里也不显示的. ...
- 在css的框中打文字,css 边框上如何写入文字?
方法一: 1.首先,打开html编辑器,新建html文件,例如:index.html. 2.在index.html中的 标签中,输入html代码:. 文字 3.浏览器运行index.html页面,此时 ...
- WPF绘制自定义窗口
原文:WPF绘制自定义窗口 WPF是制作界面的一大利器,下面就用WPF模拟一下360的软件管理界面,360软件管理界面如下: 界面不难,主要有如下几个要素: 窗体的圆角 自定义标题栏及按钮 自定义状态 ...
- 4.2第一个窗口程序
创建Win32工程和MessageBox函数 前面讲的程序都是使用控制台界面来接受输入.显示输出的.要想使用窗口界面与用户交互必须首先创建一个Win32工程. (1)运行VC++6.0,选择菜单命令& ...
- wpf之默认窗口模板研究
wpf默认的窗口模板,真的好丑好丑.但是,非常不满意的上面的边框居然不让修改.今天决定使用Blend对默认的窗口模板进行研究. 使用blend新建一个项目 右键窗口,点击编辑模板--->编辑副本 ...
- windows第一个窗口程序转自windows程序设计王艳平老师编著
转 目录: 1.窗口程序 2.分析 注册窗口类别 建立窗口 显示窗口 消息循环 窗口消息处理程序 3.注意事项 窗口程 ...
- 【第一弹】经典移植至IOS端、经典合集
前段时间比较空间,无奈手机又没有一些游戏可玩,之后就在捣鼓一些移植的游戏系列 以免以后在出现手机只能看网页的尴尬局面,也是从网上搜索,整合而至! 一部分是移植到IOS端的,一部分是经典游戏,我也顺道整 ...
最新文章
- System V的启动风格和BSD的启动风格(2)---代码角度
- 【bzoj1486】【[HNOI2009]梦幻布丁】启发式链表合并(详解)
- 分布式数据库基础:分布式事务相关概念介绍
- unlink(file_name)
- linux更改语言脚本,Linux shell脚本入门——shell语言脚本【CentOS】
- makefile编译脚本
- 切图时图片的选择:JPG、PNG、GIF的区别
- 察看无限网络linux,linux 无线网络调试
- hdu1829 A Bug's Life
- 常见Sqlite管理工具
- 【自学笔记】三维copula的构建与分布函数的求解
- Github hosts修改
- 使用ASDM 管理 ciscoASA设备
- 【游戏开发创新】用Unity等比例制作广州地铁,广州加油,早日战胜疫情(Unity | 地铁地图 | 第三人称视角)
- 【盛天体育出品】天津仁爱学院“彩虹”运动场来了
- 自学计算机图形学OpenGL(五)DDA数值微分线段法
- 微信小程序wxparse特殊解析空格,解析↵换行符号
- 前端.什么是冒泡和阻止冒泡的原因和方法
- Ubuntu 修改中文字体教程
- IF-ELSE语句的高级用法(简便写法)----前端工作问题整理