SL/WPF仿WIN8进度条

2022-05-07 16:29:10 浏览数 (1)

最近换到了win8,win8风格的进度条挺好玩的。可惜wpf上没有这个控件。那咱就自己来写一个吧。

用SL封装了个效果:

思路:这个过程可以分为3个阶段,最左边开始一个快速移动动画到中间位置,开始缓慢的做位移,然后再开始快速的飞到最右边,消失。且在第一个点缓动的时候,第二个点开始启动,依次类推,到最后一个点飞到最右边的时候,再启动第一个点。如此循环。

XAML:主要是定义4个点,以及每个点的动画。

代码语言:javascript复制
<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>
代码语言:javascript复制
</UserControl> 

cs:

代码语言:javascript复制
//作者:       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));
            }
        }
    }
} 

重点:

Storyboard在sl/WPF里面做动画的时候有很大的作用。配合DoubleAnimation可以在一段时间内改变某个对象的double型属性。比如透明值在1秒内1到0。上面例子就是做了一个在一段时间内Canvas.Left属性从0到最右边的动画。配合ColorAnimation可以在2种颜色之间做渐变。

0 人点赞