1.ProgressRing

cs代码

 [TemplateVisualState(GroupName = VisualStates.GroupActive, Name = VisualStates.StateActive)][TemplateVisualState(GroupName = VisualStates.GroupActive, Name = VisualStates.StateInactive)]public partial class ProgressRing: Control{private bool hasAppliedTemplate = false;public bool IsActive{get { return (bool)GetValue(IsActiveProperty); }set { SetValue(IsActiveProperty, value); }}// Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...public static readonly DependencyProperty IsActiveProperty =DependencyProperty.Register("IsActive", typeof(bool), typeof(ProgressRing), new PropertyMetadata(false,new PropertyChangedCallback (OnActiveChanged)));public TemplateSettingValues TemplateSettings{get { return (TemplateSettingValues)GetValue(TemplateSettingsProperty); }set { SetValue(TemplateSettingsProperty, value); }}// Using a DependencyProperty as the backing store for TemplateSettings.  This enables animation, styling, binding, etc...public static readonly DependencyProperty TemplateSettingsProperty =DependencyProperty.Register("TemplateSettings", typeof(TemplateSettingValues), typeof(ProgressRing), new PropertyMetadata(null));private static void OnActiveChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){var pr = (ProgressRing)d;var isActive = (bool)e.NewValue;pr.UpdateState(isActive);}public ProgressRing(){DefaultStyleKey = typeof(ProgressRing);TemplateSettings = new TemplateSettingValues(150);}public override void OnApplyTemplate(){base.OnApplyTemplate();hasAppliedTemplate = true;UpdateState(IsActive);}private void UpdateState(bool isActive){if (hasAppliedTemplate){string state = isActive ? VisualStates.StateActive : VisualStates.StateInactive;VisualStateManager.GoToState(this, state, true);}}}
public class TemplateSettingValues : System.Windows.DependencyObject{// Using a DependencyProperty as the backing store for MaxSideLength.  This enables animation, styling, binding, etc...public static readonly DependencyProperty MaxSideLengthProperty =DependencyProperty.Register("MaxSideLength", typeof(double), typeof(TemplateSettingValues), new PropertyMetadata(0D));// Using a DependencyProperty as the backing store for EllipseDiameter.  This enables animation, styling, binding, etc...public static readonly DependencyProperty EllipseDiameterProperty =DependencyProperty.Register("EllipseDiameter", typeof(double), typeof(TemplateSettingValues), new PropertyMetadata(0D));// Using a DependencyProperty as the backing store for EllipseOffset.  This enables animation, styling, binding, etc...public static readonly DependencyProperty EllipseOffsetProperty =DependencyProperty.Register("EllipseOffset", typeof(Thickness), typeof(TemplateSettingValues), new PropertyMetadata(default(Thickness)));public TemplateSettingValues(double width){if (width <= 40){EllipseDiameter = (width / 10) + 1;}else{EllipseDiameter = width / 10;}MaxSideLength = width - EllipseDiameter;EllipseOffset = new System.Windows.Thickness(0, EllipseDiameter * 2.5, 0, 0);}public double MaxSideLength{get { return (double)GetValue(MaxSideLengthProperty); }set { SetValue(MaxSideLengthProperty, value); }}public double EllipseDiameter{get { return (double)GetValue(EllipseDiameterProperty); }set { SetValue(EllipseDiameterProperty, value); }}public Thickness EllipseOffset{get { return (Thickness)GetValue(EllipseOffsetProperty); }set { SetValue(EllipseOffsetProperty, value); }}}

xaml代码:

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:local="clr-namespace:WpfAppStyle.ProgressRing"><Style TargetType="{x:Type local:ProgressRing}"><Setter Property="Background"Value="Transparent" /><Setter Property="Foreground"Value="{DynamicResource {x:Static SystemColors.HighlightBrushKey}}" /><Setter Property="IsHitTestVisible"Value="False" /><Setter Property="HorizontalAlignment"Value="Center" /><Setter Property="VerticalAlignment"Value="Center" /><Setter Property="MinHeight"Value="20" /><Setter Property="MinWidth"Value="20" /><Setter Property="IsTabStop"Value="False" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type local:ProgressRing}"><Border x:Name="ProgressRingRoot"Background="{TemplateBinding Background}"BorderThickness="{TemplateBinding BorderThickness}"BorderBrush="{TemplateBinding BorderBrush}"><Border.Resources><Style x:Key="ProgressRingEllipseStyle"TargetType="Ellipse"><Setter Property="Opacity" Value="0" /><Setter Property="HorizontalAlignment" Value="Left" /><Setter Property="VerticalAlignment" Value="Top" /></Style></Border.Resources><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="SizeStates"><VisualState x:Name="Large"><Storyboard><ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="SixthCircle" Storyboard.TargetProperty="Visibility"><DiscreteObjectKeyFrame KeyTime="0"><DiscreteObjectKeyFrame.Value><Visibility>Visible</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames></Storyboard></VisualState><VisualState x:Name="Small" /></VisualStateGroup><VisualStateGroup x:Name="ActiveStates"><VisualState x:Name="Inactive" /><VisualState x:Name="Active"><Storyboard RepeatBehavior="Forever"><ObjectAnimationUsingKeyFrames Duration="0" Storyboard.TargetName="Ring" Storyboard.TargetProperty="Visibility"><DiscreteObjectKeyFrame KeyTime="0"><DiscreteObjectKeyFrame.Value><Visibility>Visible</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E1" Storyboard.TargetProperty="Opacity" BeginTime="0"><DiscreteDoubleKeyFrame KeyTime="0" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E2" Storyboard.TargetProperty="Opacity" BeginTime="00:00:00.167"><DiscreteDoubleKeyFrame KeyTime="0" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E3" Storyboard.TargetProperty="Opacity" BeginTime="00:00:00.334"><DiscreteDoubleKeyFrame KeyTime="0" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E4" Storyboard.TargetProperty="Opacity" BeginTime="00:00:00.501"><DiscreteDoubleKeyFrame KeyTime="0" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E5" Storyboard.TargetProperty="Opacity" BeginTime="00:00:00.668"><DiscreteDoubleKeyFrame KeyTime="0" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E6" Storyboard.TargetProperty="Opacity" BeginTime="00:00:00.835"><DiscreteDoubleKeyFrame KeyTime="0" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.21" Value="1" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.22" Value="0" /><DiscreteDoubleKeyFrame KeyTime="0:0:3.47" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E1R" BeginTime="0" Storyboard.TargetProperty="Angle"><SplineDoubleKeyFrame KeyTime="0" Value="-110" KeySpline="0.13,0.21,0.1,0.7" /><SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="10" KeySpline="0.02,0.33,0.38,0.77" /><SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="93" /><SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="205" KeySpline="0.57,0.17,0.95,0.75" /><SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="357" KeySpline="0,0.19,0.07,0.72" /><SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="439" /><SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="585" KeySpline="0,0,0.95,0.37" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E2R" BeginTime="00:00:00.167" Storyboard.TargetProperty="Angle"><SplineDoubleKeyFrame KeyTime="0" Value="-116" KeySpline="0.13,0.21,0.1,0.7" /><SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="4" KeySpline="0.02,0.33,0.38,0.77" /><SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="87" /><SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="199" KeySpline="0.57,0.17,0.95,0.75" /><SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="351" KeySpline="0,0.19,0.07,0.72" /><SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="433" /><SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="579" KeySpline="0,0,0.95,0.37" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E3R" BeginTime="00:00:00.334" Storyboard.TargetProperty="Angle"><SplineDoubleKeyFrame KeyTime="0" Value="-122" KeySpline="0.13,0.21,0.1,0.7" /><SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="-2" KeySpline="0.02,0.33,0.38,0.77" /><SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="81" /><SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="193" KeySpline="0.57,0.17,0.95,0.75" /><SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="345" KeySpline="0,0.19,0.07,0.72" /><SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="427" /><SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="573" KeySpline="0,0,0.95,0.37" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E4R" BeginTime="00:00:00.501" Storyboard.TargetProperty="Angle"><SplineDoubleKeyFrame KeyTime="0" Value="-128" KeySpline="0.13,0.21,0.1,0.7" /><SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="-8" KeySpline="0.02,0.33,0.38,0.77" /><SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="75" /><SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="187" KeySpline="0.57,0.17,0.95,0.75" /><SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="339" KeySpline="0,0.19,0.07,0.72" /><SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="421" /><SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="567" KeySpline="0,0,0.95,0.37" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E5R" BeginTime="00:00:00.668" Storyboard.TargetProperty="Angle"><SplineDoubleKeyFrame KeyTime="0" Value="-134" KeySpline="0.13,0.21,0.1,0.7" /><SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="-14" KeySpline="0.02,0.33,0.38,0.77" /><SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="69" /><SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="181" KeySpline="0.57,0.17,0.95,0.75" /><SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="331" KeySpline="0,0.19,0.07,0.72" /><SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="415" /><SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="561" KeySpline="0,0,0.95,0.37" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E6R" BeginTime="00:00:00.835" Storyboard.TargetProperty="Angle"><SplineDoubleKeyFrame KeyTime="0" Value="-140" KeySpline="0.13,0.21,0.1,0.7" /><SplineDoubleKeyFrame KeyTime="0:0:0.433" Value="-20" KeySpline="0.02,0.33,0.38,0.77" /><SplineDoubleKeyFrame KeyTime="0:0:1.2" Value="63" /><SplineDoubleKeyFrame KeyTime="0:0:1.617" Value="175" KeySpline="0.57,0.17,0.95,0.75" /><SplineDoubleKeyFrame KeyTime="0:0:2.017" Value="325" KeySpline="0,0.19,0.07,0.72" /><SplineDoubleKeyFrame KeyTime="0:0:2.783" Value="409" /><SplineDoubleKeyFrame KeyTime="0:0:3.217" Value="555" KeySpline="0,0,0.95,0.37" /></DoubleAnimationUsingKeyFrames></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><Grid x:Name="Ring"Background="{TemplateBinding Background}"MaxWidth="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.MaxSideLength}"MaxHeight="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.MaxSideLength}"Visibility="Collapsed"RenderTransformOrigin=".5,.5"FlowDirection="LeftToRight"><Canvas RenderTransformOrigin=".5,.5"><Canvas.RenderTransform><RotateTransform x:Name="E1R" /></Canvas.RenderTransform><Ellipse x:Name="E1"Style="{StaticResource ProgressRingEllipseStyle}"Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"Fill="{TemplateBinding Foreground}" /></Canvas><Canvas RenderTransformOrigin=".5,.5"><Canvas.RenderTransform><RotateTransform x:Name="E2R" /></Canvas.RenderTransform><Ellipse x:Name="E2"Style="{StaticResource ProgressRingEllipseStyle}"Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"Fill="{TemplateBinding Foreground}" /></Canvas><Canvas RenderTransformOrigin=".5,.5"><Canvas.RenderTransform><RotateTransform x:Name="E3R" /></Canvas.RenderTransform><Ellipse x:Name="E3"Style="{StaticResource ProgressRingEllipseStyle}"Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"Fill="{TemplateBinding Foreground}" /></Canvas><Canvas RenderTransformOrigin=".5,.5"><Canvas.RenderTransform><RotateTransform x:Name="E4R" /></Canvas.RenderTransform><Ellipse x:Name="E4"Style="{StaticResource ProgressRingEllipseStyle}"Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"Fill="{TemplateBinding Foreground}" /></Canvas><Canvas RenderTransformOrigin=".5,.5"><Canvas.RenderTransform><RotateTransform x:Name="E5R" /></Canvas.RenderTransform><Ellipse x:Name="E5"Style="{StaticResource ProgressRingEllipseStyle}"Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"Fill="{TemplateBinding Foreground}" /></Canvas><Canvas RenderTransformOrigin=".5,.5" Visibility="Collapsed" x:Name="SixthCircle"><Canvas.RenderTransform><RotateTransform x:Name="E6R" /></Canvas.RenderTransform><Ellipse x:Name="E6"Style="{StaticResource ProgressRingEllipseStyle}"Width="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Height="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseDiameter}"Margin="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=TemplateSettings.EllipseOffset}"Fill="{TemplateBinding Foreground}" /></Canvas></Grid></Border></ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>

使用:

<Window.Resources><ResourceDictionary><ResourceDictionary.MergedDictionaries><ResourceDictionary Source="pack://application:,,,/WpfAppStyle;component/ProgressRing/ProgressRing.xaml" /></ResourceDictionary></Window.Resources><progressRing:ProgressRing IsActive="False" Width="150" Height="150" x:Name="progressRing" />

效果:

2.busyIndicator

cs代码

/// <summary>/// A control to provide a visual indicator when an application is busy./// </summary>[TemplateVisualState(Name = VisualState4BusyIndicator.StateIdle, GroupName = VisualState4BusyIndicator.GroupBusyStatus)][TemplateVisualState(Name = VisualState4BusyIndicator.StateBusy, GroupName = VisualState4BusyIndicator.GroupBusyStatus)][TemplateVisualState(Name = VisualState4BusyIndicator.StateVisible, GroupName = VisualState4BusyIndicator.GroupVisibility)][TemplateVisualState(Name = VisualState4BusyIndicator.StateHidden, GroupName = VisualState4BusyIndicator.GroupVisibility)][StyleTypedProperty(Property = "OverlayStyle", StyleTargetType = typeof(Rectangle))][StyleTypedProperty(Property = "ProgressBarStyle", StyleTargetType = typeof(ProgressBar))]public partial class BusyIndicator : ContentControl{#region Private Members/// <summary>/// Timer used to delay the initial display and avoid flickering./// </summary>private DispatcherTimer _displayAfterTimer = new DispatcherTimer();#endregion //Private Members#region Constructorsstatic BusyIndicator(){DefaultStyleKeyProperty.OverrideMetadata(typeof(BusyIndicator), new FrameworkPropertyMetadata(typeof(BusyIndicator)));}public BusyIndicator(){_displayAfterTimer.Tick += DisplayAfterTimerElapsed;}#endregion //Constructors#region Base Class Overrides/// <summary>/// Overrides the OnApplyTemplate method./// </summary>public override void OnApplyTemplate(){base.OnApplyTemplate();ChangeVisualState(false);}#endregion //Base Class Overrides#region Properties/// <summary>/// Gets or sets a value indicating whether the BusyContent is visible./// </summary>protected bool IsContentVisible{get;set;}#endregion //Properties#region Dependency Properties#region IsBusy/// <summary>/// Identifies the IsBusy dependency property./// </summary>public static readonly DependencyProperty IsBusyProperty = DependencyProperty.Register("IsBusy",typeof(bool),typeof(BusyIndicator),new PropertyMetadata(false, new PropertyChangedCallback(OnIsBusyChanged)));/// <summary>/// Gets or sets a value indicating whether the busy indicator should show./// </summary>public bool IsBusy{get{return (bool)GetValue(IsBusyProperty);}set{SetValue(IsBusyProperty, value);}}/// <summary>/// IsBusyProperty property changed handler./// </summary>/// <param name="d">BusyIndicator that changed its IsBusy.</param>/// <param name="e">Event arguments.</param>private static void OnIsBusyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e){((BusyIndicator)d).OnIsBusyChanged(e);}/// <summary>/// IsBusyProperty property changed handler./// </summary>/// <param name="e">Event arguments.</param>protected virtual void OnIsBusyChanged(DependencyPropertyChangedEventArgs e){if (IsBusy){if (DisplayAfter.Equals(TimeSpan.Zero)){// Go visible nowIsContentVisible = true;}else{// Set a timer to go visible_displayAfterTimer.Interval = DisplayAfter;_displayAfterTimer.Start();}}else{// No longer visible_displayAfterTimer.Stop();IsContentVisible = false;if (this.FocusAfterBusy != null){this.FocusAfterBusy.Dispatcher.BeginInvoke(DispatcherPriority.Input, new Action(() =>{this.FocusAfterBusy.Focus();}));}}ChangeVisualState(true);}#endregion //IsBusy#region Busy Content/// <summary>/// Identifies the BusyContent dependency property./// </summary>public static readonly DependencyProperty BusyContentProperty = DependencyProperty.Register("BusyContent",typeof(object),typeof(BusyIndicator),new PropertyMetadata(null));/// <summary>/// Gets or sets a value indicating the busy content to display to the user./// </summary>public object BusyContent{get{return (object)GetValue(BusyContentProperty);}set{SetValue(BusyContentProperty, value);}}#endregion //Busy Content#region Busy Content Template/// <summary>/// Identifies the BusyTemplate dependency property./// </summary>public static readonly DependencyProperty BusyContentTemplateProperty = DependencyProperty.Register("BusyContentTemplate",typeof(DataTemplate),typeof(BusyIndicator),new PropertyMetadata(null));/// <summary>/// Gets or sets a value indicating the template to use for displaying the busy content to the user./// </summary>public DataTemplate BusyContentTemplate{get{return (DataTemplate)GetValue(BusyContentTemplateProperty);}set{SetValue(BusyContentTemplateProperty, value);}}#endregion //Busy Content Template#region Display After/// <summary>/// Identifies the DisplayAfter dependency property./// </summary>public static readonly DependencyProperty DisplayAfterProperty = DependencyProperty.Register("DisplayAfter",typeof(TimeSpan),typeof(BusyIndicator),new PropertyMetadata(TimeSpan.FromSeconds(0.1)));/// <summary>/// Gets or sets a value indicating how long to delay before displaying the busy content./// </summary>public TimeSpan DisplayAfter{get{return (TimeSpan)GetValue(DisplayAfterProperty);}set{SetValue(DisplayAfterProperty, value);}}#endregion //Display After#region FocusAfterBusy/// <summary>/// Identifies the FocusAfterBusy dependency property./// </summary>public static readonly DependencyProperty FocusAfterBusyProperty = DependencyProperty.Register("FocusAfterBusy",typeof(Control),typeof(BusyIndicator),new PropertyMetadata(null));/// <summary>/// Gets or sets a Control that should get focus when the busy indicator disapears./// </summary>public Control FocusAfterBusy{get{return (Control)GetValue(FocusAfterBusyProperty);}set{SetValue(FocusAfterBusyProperty, value);}}#endregion //FocusAfterBusy#region Overlay Style/// <summary>/// Identifies the OverlayStyle dependency property./// </summary>public static readonly DependencyProperty OverlayStyleProperty = DependencyProperty.Register("OverlayStyle",typeof(Style),typeof(BusyIndicator),new PropertyMetadata(null));/// <summary>/// Gets or sets a value indicating the style to use for the overlay./// </summary>public Style OverlayStyle{get{return (Style)GetValue(OverlayStyleProperty);}set{SetValue(OverlayStyleProperty, value);}}#endregion //Overlay Style#region ProgressBar Style/// <summary>/// Identifies the ProgressBarStyle dependency property./// </summary>public static readonly DependencyProperty ProgressBarStyleProperty = DependencyProperty.Register("ProgressBarStyle",typeof(Style),typeof(BusyIndicator),new PropertyMetadata(null));/// <summary>/// Gets or sets a value indicating the style to use for the progress bar./// </summary>public Style ProgressBarStyle{get{return (Style)GetValue(ProgressBarStyleProperty);}set{SetValue(ProgressBarStyleProperty, value);}}#endregion //ProgressBar Style#endregion //Dependency Properties#region Methods/// <summary>/// Handler for the DisplayAfterTimer./// </summary>/// <param name="sender">Event sender.</param>/// <param name="e">Event arguments.</param>private void DisplayAfterTimerElapsed(object sender, EventArgs e){_displayAfterTimer.Stop();IsContentVisible = true;ChangeVisualState(true);}/// <summary>/// Changes the control's visual state(s)./// </summary>/// <param name="useTransitions">True if state transitions should be used.</param>protected virtual void ChangeVisualState(bool useTransitions){VisualStateManager.GoToState(this, IsBusy ? VisualState4BusyIndicator.StateBusy : VisualState4BusyIndicator.StateIdle, useTransitions);VisualStateManager.GoToState(this, IsContentVisible ? VisualState4BusyIndicator.StateVisible : VisualState4BusyIndicator.StateHidden, useTransitions);}#endregion //Methods}
 public class ProgressBarWidthConverter : IMultiValueConverter{public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture){var contentWidth = (double)values[0];var parentMinWidth = (double)values[1];return Math.Max(contentWidth, parentMinWidth);}public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture){throw new NotImplementedException();}}
public class VisualState4BusyIndicator{/// <summary>/// Busyness group name./// </summary>public const string GroupBusyStatus = "BusyStatusStates";/// <summary>/// Busy state for BusyIndicator./// </summary>public const string StateBusy = "Busy";/// <summary>/// Idle state for BusyIndicator./// </summary>public const string StateIdle = "Idle";/// <summary>/// BusyDisplay group./// </summary>public const string GroupVisibility = "VisibilityStates";/// <summary>/// Visible state name for BusyIndicator./// </summary>public const string StateVisible = "Visible";/// <summary>/// Hidden state name for BusyIndicator./// </summary>public const string StateHidden = "Hidden";}

xmal代码

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:sys="clr-namespace:System;assembly=mscorlib"xmlns:converter="clr-namespace:WpfAppStyle.Busy.Converter"xmlns:local="clr-namespace:WpfAppStyle.Busy"><converter:ProgressBarWidthConverter x:Key="ProgressBarWidthConverter" /><Style TargetType="{x:Type local:BusyIndicator}"><Setter Property="BusyContent" Value="Please wait..." /><Setter Property="IsTabStop" Value="False" /><Setter Property="Focusable" Value="False" /><Setter Property="OverlayStyle"><Setter.Value><Style TargetType="Rectangle"><Setter Property="Fill" Value="White" /><Setter Property="Opacity" Value="0.5" /></Style></Setter.Value></Setter><Setter Property="ProgressBarStyle"><Setter.Value><Style TargetType="ProgressBar"><Setter Property="IsIndeterminate" Value="True" /><Setter Property="Height" Value="15" /><Setter Property="Foreground" Value="BurlyWood"></Setter><Setter Property="Margin" Value="8,0,8,8" /></Style></Setter.Value></Setter><Setter Property="DisplayAfter" Value="00:00:00.1" /><Setter Property="HorizontalAlignment" Value="Stretch" /><Setter Property="VerticalAlignment" Value="Stretch" /><Setter Property="HorizontalContentAlignment" Value="Stretch" /><Setter Property="VerticalContentAlignment" Value="Stretch" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type local:BusyIndicator}"><Grid><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="VisibilityStates"><VisualState x:Name="Hidden"><Storyboard><ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="busycontent" Storyboard.TargetProperty="(UIElement.Visibility)"><DiscreteObjectKeyFrame KeyTime="00:00:00"><DiscreteObjectKeyFrame.Value><Visibility>Collapsed</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames><ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="overlay" Storyboard.TargetProperty="(UIElement.Visibility)"><DiscreteObjectKeyFrame KeyTime="00:00:00"><DiscreteObjectKeyFrame.Value><Visibility>Collapsed</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames></Storyboard></VisualState><VisualState x:Name="Visible"><Storyboard><ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="busycontent" Storyboard.TargetProperty="(UIElement.Visibility)"><DiscreteObjectKeyFrame KeyTime="00:00:00"><DiscreteObjectKeyFrame.Value><Visibility>Visible</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames><ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="overlay" Storyboard.TargetProperty="(UIElement.Visibility)"><DiscreteObjectKeyFrame KeyTime="00:00:00"><DiscreteObjectKeyFrame.Value><Visibility>Visible</Visibility></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames></Storyboard></VisualState></VisualStateGroup><VisualStateGroup x:Name="BusyStatusStates"><VisualState x:Name="Idle"><Storyboard><ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="content" Storyboard.TargetProperty="(Control.IsEnabled)"><DiscreteObjectKeyFrame KeyTime="00:00:00"><DiscreteObjectKeyFrame.Value><sys:Boolean>True</sys:Boolean></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames></Storyboard></VisualState><VisualState x:Name="Busy"><Storyboard><ObjectAnimationUsingKeyFrames BeginTime="00:00:00" Duration="00:00:00.001" Storyboard.TargetName="content" Storyboard.TargetProperty="(Control.IsEnabled)"><DiscreteObjectKeyFrame KeyTime="00:00:00"><DiscreteObjectKeyFrame.Value><sys:Boolean>False</sys:Boolean></DiscreteObjectKeyFrame.Value></DiscreteObjectKeyFrame></ObjectAnimationUsingKeyFrames></Storyboard></VisualState></VisualStateGroup></VisualStateManager.VisualStateGroups><ContentControl x:Name="content" Content="{TemplateBinding Content}" ContentTemplate="{TemplateBinding ContentTemplate}" HorizontalContentAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}" IsTabStop="False" Focusable="False" /><Rectangle x:Name="overlay" Style="{TemplateBinding OverlayStyle}" /><ContentPresenter x:Name="busycontent"><ContentPresenter.Content><Grid HorizontalAlignment="Center" VerticalAlignment="Center"><Border Background="White" BorderThickness="1" CornerRadius="2"><Border.BorderBrush><LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"><GradientStop Color="#FFA3AEB9" Offset="0" /><GradientStop Color="#FF8399A9" Offset="0.375" /><GradientStop Color="#FF718597" Offset="0.375" /><GradientStop Color="#FF617584" Offset="1" /></LinearGradientBrush></Border.BorderBrush><Border CornerRadius="1.5" Margin="1"><Border.Background><LinearGradientBrush StartPoint="0.5,0" EndPoint="0.5,1"><GradientStop Color="#FFF6F8F9" Offset="0.02" /><GradientStop Color="#FFB8B8B8" Offset="0.996" /></LinearGradientBrush></Border.Background><Grid x:Name="_grid" MinWidth="150"><Grid.RowDefinitions><RowDefinition /><RowDefinition Height="Auto" /></Grid.RowDefinitions><ContentPresenter x:Name="busyContent"Content="{TemplateBinding BusyContent}"ContentTemplate="{TemplateBinding BusyContentTemplate}"HorizontalAlignment="Center"Margin="8" /><ProgressBar Grid.Row="1" Style="{TemplateBinding ProgressBarStyle}" ><ProgressBar.Width><MultiBinding Converter="{StaticResource ProgressBarWidthConverter}"><Binding Path="ActualWidth"ElementName="busyContent" /><Binding Path="MinWidth"ElementName="_grid" /></MultiBinding></ProgressBar.Width></ProgressBar></Grid></Border></Border></Grid></ContentPresenter.Content></ContentPresenter></Grid></ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>

效果

3.progress

<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"xmlns:System="clr-namespace:System;assembly=mscorlib"xmlns:local="clr-namespace:WpfAppStyle.Loading"><System:Double x:Key="ProgressBarMinHeight">6</System:Double><Style TargetType="{x:Type local:Loading}"><Setter Property="Background" Value="#1FFFFFFF" /><Setter Property="BorderBrush" Value="Transparent" /><Setter Property="BorderThickness" Value="0" /><Setter Property="Foreground" Value="#FF086F9E" /><Setter Property="IsTabStop" Value="False" /><Setter Property="Maximum" Value="100" /><Setter Property="MinHeight" Value="{StaticResource ProgressBarMinHeight}" /><Setter Property="Template"><Setter.Value><ControlTemplate TargetType="{x:Type local:Loading}"><ControlTemplate.Resources><Storyboard x:Key="IndeterminateStoryboard" RepeatBehavior="Forever"><DoubleAnimation x:Name="MainDoubleAnim"Storyboard.TargetName="EllipseGrid"Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"Duration="0:0:3.917" /><DoubleAnimationUsingKeyFrames x:Name="E1Anim"Storyboard.TargetName="E1"Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="0" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:1" /><EasingDoubleKeyFrame KeyTime="0:0:2" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:3" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames x:Name="E2Anim"Storyboard.TargetName="E2"Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.167" Value="0" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:1.167" /><EasingDoubleKeyFrame KeyTime="0:0:2.167" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:3.167" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames x:Name="E3Anim"Storyboard.TargetName="E3"Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.333" Value="0" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:1.333" /><EasingDoubleKeyFrame KeyTime="0:0:2.333" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:3.333" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames x:Name="E4Anim"Storyboard.TargetName="E4"Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:1.5" /><EasingDoubleKeyFrame KeyTime="0:0:2.5" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:3.5" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames x:Name="E5Anim"Storyboard.TargetName="E5"Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.667" Value="0" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:1.667" /><EasingDoubleKeyFrame KeyTime="0:0:2.667" /><SplineDoubleKeyFrame KeySpline="0.4,0,0.6,1" KeyTime="0:0:3.667" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="B1" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="-50" /><EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:2" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:3" Value="100" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="B2" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="-50" /><EasingDoubleKeyFrame KeyTime="0:0:0.667" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:2.167" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:3.167" Value="100" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="B3" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="-50" /><EasingDoubleKeyFrame KeyTime="0:0:0.833" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:2.333" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:3.333" Value="100" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="B4" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="-50" /><EasingDoubleKeyFrame KeyTime="0:0:1" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:2.5" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:3.5" Value="100" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="B5" Storyboard.TargetProperty="(UIElement.RenderTransform).(TranslateTransform.X)"><EasingDoubleKeyFrame KeyTime="0" Value="-50" /><EasingDoubleKeyFrame KeyTime="0:0:1.167" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:2.667" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:3.667" Value="100" /></DoubleAnimationUsingKeyFrames><DoubleAnimation Storyboard.TargetName="EllipseGrid"Storyboard.TargetProperty="Opacity"To="1"Duration="0" /><DoubleAnimation Storyboard.TargetName="DeterminateRoot"Storyboard.TargetProperty="Opacity"To="0"Duration="0" /><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E1" Storyboard.TargetProperty="Opacity"><EasingDoubleKeyFrame KeyTime="0" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E2" Storyboard.TargetProperty="Opacity"><EasingDoubleKeyFrame KeyTime="0" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.167" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.167" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3.167" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3.167" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E3" Storyboard.TargetProperty="Opacity"><EasingDoubleKeyFrame KeyTime="0" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.333" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.333" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3.333" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3.333" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E4" Storyboard.TargetProperty="Opacity"><EasingDoubleKeyFrame KeyTime="0" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.5" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3.5" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3.5" Value="0" /></DoubleAnimationUsingKeyFrames><DoubleAnimationUsingKeyFrames Storyboard.TargetName="E5" Storyboard.TargetProperty="Opacity"><EasingDoubleKeyFrame KeyTime="0" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.667" Value="0" /><EasingDoubleKeyFrame KeyTime="0:0:0.667" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3.667" Value="1" /><EasingDoubleKeyFrame KeyTime="0:0:3.667" Value="0" /></DoubleAnimationUsingKeyFrames></Storyboard></ControlTemplate.Resources><Grid x:Name="ContainingGrid"><Grid x:Name="EllipseClip" ClipToBounds="True"><Grid x:Name="EllipseGrid" Opacity="0"><Grid.ColumnDefinitions><ColumnDefinition Width="Auto" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="Auto" /><ColumnDefinition Width="Auto" /></Grid.ColumnDefinitions><Grid.RenderTransform><TranslateTransform /></Grid.RenderTransform><Border x:Name="B1"Grid.Column="8"RenderTransformOrigin="0.5,0.5"><Border.RenderTransform><TranslateTransform /></Border.RenderTransform><Ellipse x:Name="E1"Width="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Fill="{TemplateBinding Foreground}"RenderTransformOrigin="0.5,0.5"><Ellipse.RenderTransform><TranslateTransform /></Ellipse.RenderTransform></Ellipse></Border><Rectangle Grid.Column="7" Width="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}" /><Border x:Name="B2"Grid.Column="6"RenderTransformOrigin="0.5,0.5"><Border.RenderTransform><TranslateTransform /></Border.RenderTransform><Ellipse x:Name="E2"Width="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Fill="{TemplateBinding Foreground}"RenderTransformOrigin="0.5,0.5"><Ellipse.RenderTransform><TranslateTransform /></Ellipse.RenderTransform></Ellipse></Border><Rectangle Grid.Column="5" Width="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}" /><Border x:Name="B3"Grid.Column="4"RenderTransformOrigin="0.5,0.5"><Border.RenderTransform><TranslateTransform /></Border.RenderTransform><Ellipse x:Name="E3"Width="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Fill="{TemplateBinding Foreground}"RenderTransformOrigin="0.5,0.5"><Ellipse.RenderTransform><TranslateTransform /></Ellipse.RenderTransform></Ellipse></Border><Rectangle Grid.Column="3" Width="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}" /><Border x:Name="B4"Grid.Column="2"RenderTransformOrigin="0.5,0.5"><Border.RenderTransform><TranslateTransform /></Border.RenderTransform><Ellipse x:Name="E4"Width="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Fill="{TemplateBinding Foreground}"RenderTransformOrigin="0.5,0.5"><Ellipse.RenderTransform><TranslateTransform /></Ellipse.RenderTransform></Ellipse></Border><Rectangle Grid.Column="1" Width="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}" /><Border x:Name="B5"Grid.Column="0"RenderTransformOrigin="0.5,0.5"><Border.RenderTransform><TranslateTransform /></Border.RenderTransform><Ellipse x:Name="E5"Width="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"Fill="{TemplateBinding Foreground}"RenderTransformOrigin="0.5,0.5"><Ellipse.RenderTransform><TranslateTransform /></Ellipse.RenderTransform></Ellipse></Border></Grid></Grid><Grid x:Name="DeterminateRoot"Margin="{TemplateBinding Padding}"Opacity="0"><Border x:Name="PART_Track"Background="{TemplateBinding Background}"BorderBrush="{TemplateBinding BorderBrush}"BorderThickness="{TemplateBinding BorderThickness}" /><Rectangle x:Name="PART_Indicator"HorizontalAlignment="Left"Fill="{TemplateBinding Foreground}" /></Grid><VisualStateManager.VisualStateGroups><VisualStateGroup x:Name="CommonStates"><VisualState x:Name="Determinate" /><VisualState x:Name="Indeterminate" /></VisualStateGroup></VisualStateManager.VisualStateGroups></Grid><ControlTemplate.Triggers><Trigger Property="IsIndeterminate" Value="False"><Setter TargetName="DeterminateRoot" Property="Opacity" Value="1" /></Trigger><Trigger Property="Orientation" Value="Vertical"><Setter Property="MinHeight" Value="0" /><Setter Property="MinWidth" Value="{StaticResource ProgressBarMinHeight}" /><Setter Property="UseLayoutRounding" Value="True" /><Setter TargetName="ContainingGrid" Property="LayoutTransform"><Setter.Value><RotateTransform Angle="-90" /></Setter.Value></Setter></Trigger></ControlTemplate.Triggers></ControlTemplate></Setter.Value></Setter></Style>
</ResourceDictionary>
 public class Loading : ProgressBar{public static readonly DependencyProperty EllipseDiameterProperty= DependencyProperty.Register(nameof(EllipseDiameter),typeof(double),typeof(Loading),new PropertyMetadata(default(double)));public static readonly DependencyProperty EllipseOffsetProperty =DependencyProperty.Register(nameof(EllipseOffset),typeof(double),typeof(Loading),new PropertyMetadata(default(double)));private readonly object lockme = new object();private Storyboard indeterminateStoryboard;static Loading(){DefaultStyleKeyProperty.OverrideMetadata(typeof(Loading), new FrameworkPropertyMetadata(typeof(Loading)));IsIndeterminateProperty.OverrideMetadata(typeof(Loading), new FrameworkPropertyMetadata(OnIsIndeterminateChanged));}public Loading(){this.IsVisibleChanged += this.VisibleChangedHandler;}private void VisibleChangedHandler(object sender, DependencyPropertyChangedEventArgs e){// reset Storyboard if Visibility is set to Visible #1300if (this.IsIndeterminate){ToggleIndeterminate(this, (bool)e.OldValue, (bool)e.NewValue);}}private static void OnIsIndeterminateChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e){var bar = (Loading)dependencyObject;if (bar.IsLoaded && bar.IsVisible){ToggleIndeterminate(bar, (bool)e.OldValue, (bool)e.NewValue);}}private static void ToggleIndeterminate(Loading bar, bool oldValue, bool newValue){if (newValue == oldValue){return;}var indeterminateState = bar.GetIndeterminate();var containingObject = bar.GetTemplateChild("ContainingGrid") as FrameworkElement;if (indeterminateState != null && containingObject != null){var resetAction = new Action(() =>{if (oldValue && indeterminateState.Storyboard != null){// remove the previous storyboard from the Grid #1855indeterminateState.Storyboard.Stop(containingObject);indeterminateState.Storyboard.Remove(containingObject);}if (newValue){bar.ResetStoryboard(bar.ActualSize(true), false);}});resetAction?.Invoke();}}/// <summary>/// Gets/sets the diameter of the ellipses used in the indeterminate animation./// </summary>public double EllipseDiameter{get { return (double)this.GetValue(EllipseDiameterProperty); }set { this.SetValue(EllipseDiameterProperty, value); }}/// <summary>/// Gets/sets the offset of the ellipses used in the indeterminate animation./// </summary>public double EllipseOffset{get { return (double)this.GetValue(EllipseOffsetProperty); }set { this.SetValue(EllipseOffsetProperty, value); }}private void SizeChangedHandler(object sender, SizeChangedEventArgs e){var size = this.ActualSize(false);var bar = this;if (this.Visibility == Visibility.Visible && this.IsIndeterminate){bar.ResetStoryboard(size, true);}}private double ActualSize(bool invalidateMeasureArrange){if (invalidateMeasureArrange){this.UpdateLayout();this.Measure(new Size(double.PositiveInfinity, double.PositiveInfinity));this.InvalidateArrange();}return this.Orientation == Orientation.Horizontal ? this.ActualWidth : this.ActualHeight;}private void ResetStoryboard(double width, bool removeOldStoryboard){if (!this.IsIndeterminate){return;}lock (this.lockme){//perform calculationsvar containerAnimStart = this.CalcContainerAnimStart(width);var containerAnimEnd = this.CalcContainerAnimEnd(width);var ellipseAnimWell = this.CalcEllipseAnimWell(width);var ellipseAnimEnd = this.CalcEllipseAnimEnd(width);//reset the main double animationtry{var indeterminate = this.GetIndeterminate();if (indeterminate != null && this.indeterminateStoryboard != null){var newStoryboard = this.indeterminateStoryboard.Clone();var doubleAnim = newStoryboard.Children.First(t => t.Name == "MainDoubleAnim");doubleAnim.SetValue(DoubleAnimation.FromProperty, containerAnimStart);doubleAnim.SetValue(DoubleAnimation.ToProperty, containerAnimEnd);var namesOfElements = new[] { "E1", "E2", "E3", "E4", "E5" };foreach (var elemName in namesOfElements){var doubleAnimParent = (DoubleAnimationUsingKeyFrames)newStoryboard.Children.First(t => t.Name == elemName + "Anim");DoubleKeyFrame first,second,third;if (elemName == "E1"){first = doubleAnimParent.KeyFrames[1];second = doubleAnimParent.KeyFrames[2];third = doubleAnimParent.KeyFrames[3];}else{first = doubleAnimParent.KeyFrames[2];second = doubleAnimParent.KeyFrames[3];third = doubleAnimParent.KeyFrames[4];}first.Value = ellipseAnimWell;second.Value = ellipseAnimWell;third.Value = ellipseAnimEnd;first.InvalidateProperty(DoubleKeyFrame.ValueProperty);second.InvalidateProperty(DoubleKeyFrame.ValueProperty);third.InvalidateProperty(DoubleKeyFrame.ValueProperty);doubleAnimParent.InvalidateProperty(Storyboard.TargetPropertyProperty);doubleAnimParent.InvalidateProperty(Storyboard.TargetNameProperty);}var containingGrid = (FrameworkElement)this.GetTemplateChild("ContainingGrid");if (removeOldStoryboard && indeterminate.Storyboard != null){// remove the previous storyboard from the Grid #1855indeterminate.Storyboard.Stop(containingGrid);indeterminate.Storyboard.Remove(containingGrid);}indeterminate.Storyboard = newStoryboard;indeterminate.Storyboard?.Begin(containingGrid, true);}}catch (Exception){//we just ignore }}}private VisualState GetIndeterminate(){var templateGrid = this.GetTemplateChild("ContainingGrid") as FrameworkElement;if (templateGrid == null){this.ApplyTemplate();templateGrid = this.GetTemplateChild("ContainingGrid") as FrameworkElement;if (templateGrid == null) return null;}var groups = VisualStateManager.GetVisualStateGroups(templateGrid);return groups?.OfType<VisualStateGroup>().SelectMany(group => group.States.OfType<VisualState>()).FirstOrDefault(state => state.Name == "Indeterminate");}private void SetEllipseDiameter(double width){this.SetCurrentValue(EllipseDiameterProperty, width <= 180 ? 4d : (width <= 280 ? 5d : 6d));}private void SetEllipseOffset(double width){this.SetCurrentValue(EllipseOffsetProperty, width <= 180 ? 4d : (width <= 280 ? 7d : 9d));}private double CalcContainerAnimStart(double width){return width <= 180 ? -34 : (width <= 280 ? -50.5 : -63);}private double CalcContainerAnimEnd(double width){var firstPart = 0.4352 * width;return width <= 180 ? firstPart - 25.731 : (width <= 280 ? firstPart + 27.84 : firstPart + 58.862);}private double CalcEllipseAnimWell(double width){return width * 1.0 / 3.0;}private double CalcEllipseAnimEnd(double width){return width * 2.0 / 3.0;}public override void OnApplyTemplate(){base.OnApplyTemplate();lock (this.lockme){this.indeterminateStoryboard = this.TryFindResource("IndeterminateStoryboard") as Storyboard;}this.Loaded -= this.LoadedHandler;this.Loaded += this.LoadedHandler;}private void LoadedHandler(object sender, RoutedEventArgs routedEventArgs){this.Loaded -= this.LoadedHandler;this.SizeChangedHandler(null, null);this.SizeChanged += this.SizeChangedHandler;}protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo){base.OnRenderSizeChanged(sizeInfo);this.UpdateEllipseProperties();}private void UpdateEllipseProperties(){// Update the Ellipse properties to their default values// only if they haven't been user-set.var actualSize = this.ActualSize(true);if (actualSize > 0){if (this.EllipseDiameter.Equals(0)){this.SetEllipseDiameter(actualSize);}if (this.EllipseOffset.Equals(0)){this.SetEllipseOffset(actualSize);}}}}

效果(使用时IsIndeterminate="True")

wpf 三种 loading 样式相关推荐

  1. HTML三种引入样式的方式

    HTML三种引入样式的方式 1.外部样式:是通过link元素引入 <link rel="stylesheet" type="text/css" href= ...

  2. css代码价格,CSS三种价格表样式-CSS应用实例

    CSS三种价格表样式-CSS应用实例 搞代码-CSS三种价格表样式-CSS应用实例(gaodaima.com) * { box-sizing: border-box; } .columns { flo ...

  3. Python可视化中Matplotlib(4.三种设置样式方法、设置坐标刻度以及标签、设置显示出特殊字符)

    1.三种设置方式 (1)向方法传入关键字参数 上一节已经总结过,一直在使用 (2)对实例使用一系列的setter方法 具体的方法直接看代码 import matplotlib.pyplot as pl ...

  4. 三种CSS样式的引用方式

    CSS样式 3种引用样式的好处及区别: 外部引入样式 优点:代码易于管理和维护,一个CSS能控制多个页面.提高加载速度. 缺点:当外部CSS过多时会造成服务器的请求压力. 头部引入样式: .  优点: ...

  5. 三种 Loading 制作方案

    作者:JS_Even_JS 来源:https://segmentfault.com/a/1190000038692080 一.简介 Loading几乎是每个应用都会用到的一个组件.很多组件库都会提供相 ...

  6. 三种css样式表及其优先级

    1.行内样式 body内: <p style="text-indent: 2em;color: red"> 我是行内样式 </p> 2.内部样式表 body ...

  7. 你真的知道css三种存在样式(外联样式、内部样式、内联样式)的区别吗?

    css样式在html中有三种存在形态: 内联样式:<div style="display: none"></div> 内部样式: <style> ...

  8. JS原生轮播图(三种不同样式)

    文章目录 前言 轮播图展示 源码(可直接使用) 轮播图01 轮播图02,03 前言 原生js制作的轮播图,不需要引入插件. 实现功能: 1)定时器效果,隔一秒转下一张图 2)鼠标移上去停止轮播,离开则 ...

  9. html的三种样式定义方式:外部样式表;内部样式表;内联样式表

    html.css.javascript是网页中的三个基础,他们分别是数据.样式.行为. css样式分为三种 style.html <!--作者:948228952@qq.com时间:2015-0 ...

最新文章

  1. 被解放的姜戈02 庄园疑云
  2. IntelliJ IDEA 、 Android Stadio 不显示Version Contro窗口
  3. python实现将文件内容按照某一列内容的大小值重新排序_Python数据分析入门教程(四):数值操作...
  4. 100万“愤怒的小鸟”:中国手机开发者生存调查
  5. 让 .Net 更方便的导入导出Excel
  6. 来,一起“八卦”一下数据湖
  7. Redis实现消息队列和订阅发布模式
  8. string查找字符(串)
  9. 程序员在网吧办公是什么感觉?网友:在被打的边缘疯狂试探!
  10. UVA 254 Towers of Hanoi
  11. linux的mysql不允许连接_linux下允许mysql远程连接
  12. 【狂神说Java】Docker最新超详细版教程通俗易懂笔记
  13. Python数据分析之时间处理技巧1,2,3
  14. 阿里云飞天系统的技术架构
  15. 【Python学习笔记②】——基础的数据结构【两万字总结 + 字符串、列表、元组、字典 + 增删查改】
  16. 微信小程序接入腾讯云MQTT服务
  17. uni-app提交表单成功之后跳转首页
  18. android gettext方法,android – getString()和getText()有什么区别?
  19. 软考高级 真题 2010年下半年 信息系统项目管理师 案例分析
  20. oracle rac 火星舱_火星高科数据保护技术使火星舱助用户完全解决相关需求

热门文章

  1. 综合布线系统带宽与计算机网络带宽计算题,计算机网络思考与练习题.doc
  2. Android中监听电源键长按、Home键、Home键长按
  3. 骨传导耳机的缺点有哪些?骨传导耳机的优缺点分析
  4. 电子学会2022年12月青少年软件编程(图形化)等级考试试卷(一级)答案解析
  5. 【Python免费网站】2021学习python 5个绝佳的网站,新手小白再也不怕学不会!
  6. Golang 给视频添加背景音乐 | Golang工具
  7. 广发卡知识知多少?不懂来看,不然吃亏了!
  8. 【华为机试022】简单密码破解
  9. 致家长--为什么选择Scratch
  10. usb相机的经验总结