最近换到了win8,win8风格的进度条挺好玩的。可惜wpf上没有这个控件。那咱就自己来写一个吧。
用SL封装了个效果:
思路:这个过程可以分为3个阶段,最左边开始一个快速移动动画到中间位置,开始缓慢的做位移,然后再开始快速的飞到最右边,消失。且在第一个点缓动的时候,第二个点开始启动,依次类推,到最后一个点飞到最右边的时候,再启动第一个点。如此循环。
XAML:主要是定义4个点,以及每个点的动画。
<UserControl x:Class="Win8ProcessBar.CtlWin8ProcessBar"
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Height="20" Loaded="UserControl_Loaded" Initialized="CtlWin8ProcessBar_OnInitialized">
<Canvas>
<Ellipse x:Name="el" Width="6" Height="6" Fill="Black" Canvas.Top="7" Canvas.Left="0" Opacity="0">
<Ellipse.Resources>
<Storyboard x:Key="sbLeft" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el">
<DoubleAnimation From="{Binding Path=LeftFrom, Mode=OneWay}" To="{ Binding Path=LeftTo, Mode=OneWay}" Duration="0:0:0.25">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="sbSlow" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el">
<DoubleAnimation From="{Binding Path=SlowFrom, Mode=OneWay}" To="{ Binding Path=SlowTo, Mode=OneWay}" Duration="0:0:1">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="sbRight" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el">
<DoubleAnimation From="{Binding Path=RightFrom, Mode=OneWay}" To="{ Binding Path=RightTo, Mode=OneWay}" Duration="0:0:0.25">
</DoubleAnimation>
</Storyboard>
</Ellipse.Resources>
</Ellipse>
<Ellipse x:Name="el1" Width="6" Height="6" Fill="Black" Canvas.Top="7" Canvas.Left="0" Opacity="0">
<Ellipse.Resources>
<Storyboard x:Key="sbLeft1" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el1">
<DoubleAnimation From="{Binding Path=LeftFrom, Mode=OneWay}" To="{ Binding Path=LeftTo, Mode=OneWay}" Duration="0:0:0.25">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="sbSlow1" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el1">
<DoubleAnimation From="{Binding Path=SlowFrom, Mode=OneWay}" To="{ Binding Path=SlowTo, Mode=OneWay}" Duration="0:0:1">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="sbRight1" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el1">
<DoubleAnimation From="{Binding Path=RightFrom, Mode=OneWay}" To="{ Binding Path=RightTo, Mode=OneWay}" Duration="0:0:0.25">
</DoubleAnimation>
</Storyboard>
</Ellipse.Resources>
</Ellipse>
===========================================这里省略2个点的定义==================================================
</Canvas>
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"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300" Height="20" Loaded="UserControl_Loaded" Initialized="CtlWin8ProcessBar_OnInitialized">
<Canvas>
<Ellipse x:Name="el" Width="6" Height="6" Fill="Black" Canvas.Top="7" Canvas.Left="0" Opacity="0">
<Ellipse.Resources>
<Storyboard x:Key="sbLeft" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el">
<DoubleAnimation From="{Binding Path=LeftFrom, Mode=OneWay}" To="{ Binding Path=LeftTo, Mode=OneWay}" Duration="0:0:0.25">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="sbSlow" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el">
<DoubleAnimation From="{Binding Path=SlowFrom, Mode=OneWay}" To="{ Binding Path=SlowTo, Mode=OneWay}" Duration="0:0:1">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="sbRight" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el">
<DoubleAnimation From="{Binding Path=RightFrom, Mode=OneWay}" To="{ Binding Path=RightTo, Mode=OneWay}" Duration="0:0:0.25">
</DoubleAnimation>
</Storyboard>
</Ellipse.Resources>
</Ellipse>
<Ellipse x:Name="el1" Width="6" Height="6" Fill="Black" Canvas.Top="7" Canvas.Left="0" Opacity="0">
<Ellipse.Resources>
<Storyboard x:Key="sbLeft1" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el1">
<DoubleAnimation From="{Binding Path=LeftFrom, Mode=OneWay}" To="{ Binding Path=LeftTo, Mode=OneWay}" Duration="0:0:0.25">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="sbSlow1" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el1">
<DoubleAnimation From="{Binding Path=SlowFrom, Mode=OneWay}" To="{ Binding Path=SlowTo, Mode=OneWay}" Duration="0:0:1">
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="sbRight1" Storyboard.TargetProperty="(Canvas.Left)" Storyboard.TargetName="el1">
<DoubleAnimation From="{Binding Path=RightFrom, Mode=OneWay}" To="{ Binding Path=RightTo, Mode=OneWay}" Duration="0:0:0.25">
</DoubleAnimation>
</Storyboard>
</Ellipse.Resources>
</Ellipse>
===========================================这里省略2个点的定义==================================================
</Canvas>
</UserControl>
cs:
//作者: minjie.zhou
// 创建时间: 2013/4/21 23:51:59
namespace Win8ProcessBar
{
/// <summary>
/// UProgressBar.xaml 的交互逻辑
/// </summary>
public partial class CtlWin8ProcessBar : UserControl, INotifyPropertyChanged
{
public CtlWin8ProcessBar()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if (double.IsNaN(Width))//默认为400的宽度
{
Width = 400;
}
LeftFrom = 0;
LeftTo = Width / 2 - (Width /7) / 2;
SlowFrom = LeftTo;
SlowTo = LeftTo + (Width / 7);
RightFrom = SlowTo;
RightTo = Width;
Start();
}
#region 属性
private double _leftFrom;
/// <summary>
/// 左边第一个起点
/// </summary>
public double LeftFrom
{
get { return _leftFrom; }
set
{
_leftFrom = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("LeftFrom");
}
}
}
private double _leftTo;
/// <summary>
/// 第一个终点
/// </summary>
public double LeftTo
{
get
{
return _leftTo;
}
set
{
_leftTo = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("LeftTo");
}
}
}
private double _slowFrom;
/// <summary>
/// 缓动起点
/// </summary>
public double SlowFrom
{
get
{
return _slowFrom;
}
set
{
_slowFrom = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("SlowFrom");
}
}
}
private double _slowTo;
/// <summary>
/// 缓动终点
/// </summary>
public double SlowTo
{
get
{
return _slowTo;
}
set
{
_slowTo = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("SlowTo");
}
}
}
private double _rightFrom;
/// <summary>
/// 右边起点
/// </summary>
public double RightFrom
{
get
{
return _rightFrom;
}
set
{
_rightFrom = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("RightFrom");
}
}
}
private double _rightTo;
/// <summary>
/// 右边终点
/// </summary>
public double RightTo
{
get
{
return _rightTo;
}
set
{
_rightTo = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("RightTo");
}
}
}
#endregion
private void CtlWin8ProcessBar_OnInitialized(object sender, EventArgs e)
{
this.DataContext = this;
this.el.Opacity = 0;
this.el1.Opacity = 0;
this.el2.Opacity = 0;
this.el3.Opacity = 0;
var sbLeft = this.el.FindResource("sbLeft") as Storyboard;
var sbSlow = this.el.FindResource("sbSlow") as Storyboard;
var sbRight = this.el.FindResource("sbRight") as Storyboard;
var sbLeft1 = this.el1.FindResource("sbLeft1") as Storyboard;
var sbSlow1 = this.el1.FindResource("sbSlow1") as Storyboard;
var sbRight1 = this.el1.FindResource("sbRight1") as Storyboard;
var sbLeft2 = this.el2.FindResource("sbLeft2") as Storyboard;
var sbSlow2 = this.el2.FindResource("sbSlow2") as Storyboard;
var sbRight2 = this.el2.FindResource("sbRight2") as Storyboard;
var sbLeft3 = this.el3.FindResource("sbLeft3") as Storyboard;
var sbSlow3 = this.el3.FindResource("sbSlow3") as Storyboard;
var sbRight3 = this.el3.FindResource("sbRight3") as Storyboard;
//第一个点第一个动画结束后开启缓动,第二个点启动
sbLeft.Completed += (a, b) =>
{
sbSlow.Begin();
el1.Opacity = 1;
sbLeft1.Begin();
};
//第一个点缓动结束,右边动画启动
sbSlow.Completed += (a, b) => sbRight.Begin();
sbRight.Completed += (a, b) => el.Opacity = 0;
//以下类推
sbLeft1.Completed += (a, b) =>
{
sbSlow1.Begin();
el2.Opacity = 1;
sbLeft2.Begin();
};
sbSlow1.Completed += (a, b) => sbRight1.Begin();
sbRight1.Completed += (a, b) => el1.Opacity = 0;
sbLeft2.Completed += (a, b) =>
{
sbSlow2.Begin();
el3.Opacity = 1;
sbLeft3.Begin();
};
sbSlow2.Completed += (a, b) => sbRight2.Begin();
sbRight2.Completed += (a, b) => el2.Opacity = 0;
sbLeft3.Completed += (a, b) => sbSlow3.Begin();
sbSlow3.Completed += (a, b) => sbRight3.Begin();
//最后一个点动画结束,第一个点重启 如此循环
sbRight3.Completed += (a, b) =>
{
el3.Opacity = 0;
el.Opacity = 1;
sbLeft.Begin();
};
}
public void Start()
{
var sb = this.el.FindResource("sbLeft") as Storyboard;
this.el.Opacity = 1;
if (sb != null)
sb.Begin();
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
// 创建时间: 2013/4/21 23:51:59
namespace Win8ProcessBar
{
/// <summary>
/// UProgressBar.xaml 的交互逻辑
/// </summary>
public partial class CtlWin8ProcessBar : UserControl, INotifyPropertyChanged
{
public CtlWin8ProcessBar()
{
InitializeComponent();
}
private void UserControl_Loaded(object sender, RoutedEventArgs e)
{
if (double.IsNaN(Width))//默认为400的宽度
{
Width = 400;
}
LeftFrom = 0;
LeftTo = Width / 2 - (Width /7) / 2;
SlowFrom = LeftTo;
SlowTo = LeftTo + (Width / 7);
RightFrom = SlowTo;
RightTo = Width;
Start();
}
#region 属性
private double _leftFrom;
/// <summary>
/// 左边第一个起点
/// </summary>
public double LeftFrom
{
get { return _leftFrom; }
set
{
_leftFrom = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("LeftFrom");
}
}
}
private double _leftTo;
/// <summary>
/// 第一个终点
/// </summary>
public double LeftTo
{
get
{
return _leftTo;
}
set
{
_leftTo = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("LeftTo");
}
}
}
private double _slowFrom;
/// <summary>
/// 缓动起点
/// </summary>
public double SlowFrom
{
get
{
return _slowFrom;
}
set
{
_slowFrom = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("SlowFrom");
}
}
}
private double _slowTo;
/// <summary>
/// 缓动终点
/// </summary>
public double SlowTo
{
get
{
return _slowTo;
}
set
{
_slowTo = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("SlowTo");
}
}
}
private double _rightFrom;
/// <summary>
/// 右边起点
/// </summary>
public double RightFrom
{
get
{
return _rightFrom;
}
set
{
_rightFrom = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("RightFrom");
}
}
}
private double _rightTo;
/// <summary>
/// 右边终点
/// </summary>
public double RightTo
{
get
{
return _rightTo;
}
set
{
_rightTo = value;
if (this.PropertyChanged != null)
{
NotifyPropertyChanged("RightTo");
}
}
}
#endregion
private void CtlWin8ProcessBar_OnInitialized(object sender, EventArgs e)
{
this.DataContext = this;
this.el.Opacity = 0;
this.el1.Opacity = 0;
this.el2.Opacity = 0;
this.el3.Opacity = 0;
var sbLeft = this.el.FindResource("sbLeft") as Storyboard;
var sbSlow = this.el.FindResource("sbSlow") as Storyboard;
var sbRight = this.el.FindResource("sbRight") as Storyboard;
var sbLeft1 = this.el1.FindResource("sbLeft1") as Storyboard;
var sbSlow1 = this.el1.FindResource("sbSlow1") as Storyboard;
var sbRight1 = this.el1.FindResource("sbRight1") as Storyboard;
var sbLeft2 = this.el2.FindResource("sbLeft2") as Storyboard;
var sbSlow2 = this.el2.FindResource("sbSlow2") as Storyboard;
var sbRight2 = this.el2.FindResource("sbRight2") as Storyboard;
var sbLeft3 = this.el3.FindResource("sbLeft3") as Storyboard;
var sbSlow3 = this.el3.FindResource("sbSlow3") as Storyboard;
var sbRight3 = this.el3.FindResource("sbRight3") as Storyboard;
//第一个点第一个动画结束后开启缓动,第二个点启动
sbLeft.Completed += (a, b) =>
{
sbSlow.Begin();
el1.Opacity = 1;
sbLeft1.Begin();
};
//第一个点缓动结束,右边动画启动
sbSlow.Completed += (a, b) => sbRight.Begin();
sbRight.Completed += (a, b) => el.Opacity = 0;
//以下类推
sbLeft1.Completed += (a, b) =>
{
sbSlow1.Begin();
el2.Opacity = 1;
sbLeft2.Begin();
};
sbSlow1.Completed += (a, b) => sbRight1.Begin();
sbRight1.Completed += (a, b) => el1.Opacity = 0;
sbLeft2.Completed += (a, b) =>
{
sbSlow2.Begin();
el3.Opacity = 1;
sbLeft3.Begin();
};
sbSlow2.Completed += (a, b) => sbRight2.Begin();
sbRight2.Completed += (a, b) => el2.Opacity = 0;
sbLeft3.Completed += (a, b) => sbSlow3.Begin();
sbSlow3.Completed += (a, b) => sbRight3.Begin();
//最后一个点动画结束,第一个点重启 如此循环
sbRight3.Completed += (a, b) =>
{
el3.Opacity = 0;
el.Opacity = 1;
sbLeft.Begin();
};
}
public void Start()
{
var sb = this.el.FindResource("sbLeft") as Storyboard;
this.el.Opacity = 1;
if (sb != null)
sb.Begin();
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged(String propertyName = "")
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
}
重点:
Storyboard在sl/WPF里面做动画的时候有很大的作用。配合DoubleAnimation可以在一段时间内改变某个对象的double型属性。比如透明值在1秒内1到0。上面例子就是做了一个在一段时间内Canvas.Left属性从0到最右边的动画。配合ColorAnimation可以在2种颜色之间做渐变。