原文 http://www.cnblogs.com/kklldog/archive/2013/04/22/3036778.html
最近换到了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));
}
}
}
}
重点:
Sotryboard在sl/WPF里面做动画的时候有很大的作用。配合DoubleAnimation可以在一段时间内改变某个对象的double型属性。比如透明值在1秒内1到0。上面例子就是做了一个在一段时间内Canvas.Left属性从0到最右边的动画。配合ColorAnimation可以在2种颜色之间做渐变。