第一句子网 - 唯美句子、句子迷、好句子大全
第一句子网 > 好玩的WPF第一弹:窗体抖动+边框阴影效果+倒计时显示文字

好玩的WPF第一弹:窗体抖动+边框阴影效果+倒计时显示文字

时间:2019-11-01 21:43:23

相关推荐

好玩的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="/winfx//xaml/presentation"xmlns:x="/winfx//xaml"xmlns:mc="/markup-compatibility/" xmlns:d="/expression/blend/" 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);

最后就是注冊事件咯:

pleted += 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);

好了,博客结束啦,我也写了好久。要源代码的话就在评论里留邮箱吧……我一个一个发了……


感谢您的訪问,希望对您有所帮助。 欢迎大家关注、收藏以及评论。

为使本文得到斧正和提问,转载请注明出处:

/nomasp

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。