zoukankan      html  css  js  c++  java
  • WPF自定义控件与样式(11)-等待/忙/正在加载状态-控件实现

    一.前言

      申明:WPF自定义控件与样式是一个系列文章,前后是有些关联的,但大多是按照由简到繁的顺序逐步发布的等,若有不明白的地方可以参考本系列前面的文章,文末附有部分文章链接。

      本文主要有三种实现方式

    • 简单忙碌状态控件BusyBox;
    • Win8/win10效果忙碌状态控件ProgressRing;
    • 弹出异步等待框WaitingBox;

    二.简单忙碌状态控件BusyBox

      效果图:

     

      通过属性"IsActive"控制控件是否启用,后台C#代码:  

    复制代码
        /// <summary>
        /// BusyBox.xaml 的交互逻辑
        /// </summary>
        public partial class BusyBox : UserControl
        {
            public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register("IsActive", typeof(bool), typeof(BusyBox), new PropertyMetadata(false));
            /// <summary>
            /// 是否启用
            /// </summary>
            public bool IsActive
            {
                get { return (bool)GetValue(IsActiveProperty); }
                set { SetValue(IsActiveProperty, value); }
            }
    
            static BusyBox()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(BusyBox), new FrameworkPropertyMetadata(typeof(BusyBox)));
            }
        }
    复制代码

      使用了一个字体图标,触发器中实现动画显示的控制,样式代码:  

    复制代码
        <Style TargetType="{x:Type local:BusyBox}">
            <Setter Property="Foreground" Value="{StaticResource TextForeground}"></Setter>
            <Setter Property="Width" Value="32"></Setter>
            <Setter Property="Height" Value="32"></Setter>
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="{x:Type local:BusyBox}">
                        <Grid VerticalAlignment="Center" HorizontalAlignment="Center" >
                            <Viewbox Stretch="Uniform"  VerticalAlignment="Center" HorizontalAlignment="Center">
                                <TextBlock Text="&#xe65f;" x:Name="FIcon" FontSize="36" Style="{StaticResource FIcon}"  RenderTransformOrigin="0.5,0.5"
                           Foreground="{TemplateBinding Foreground}">
                                    <TextBlock.RenderTransform>
                                        <RotateTransform x:Name="TransFIcon" Angle="0"/>
                                    </TextBlock.RenderTransform>
                                </TextBlock>
                            </Viewbox>
                        </Grid>
                        <ControlTemplate.Triggers>
                            <!--激活状态-->
                            <Trigger Property="IsActive" Value="true">
                                <Setter Property="Visibility" Value="Visible" TargetName="FIcon"/>
                                <Trigger.EnterActions>
                                    <BeginStoryboard >
                                        <Storyboard >
                                            <DoubleAnimation RepeatBehavior="Forever" Storyboard.TargetName="TransFIcon" 
                                         Storyboard.TargetProperty="Angle" To="360" Duration="0:0:2.5"/>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </Trigger.EnterActions>
                                <Trigger.ExitActions>
                                    <BeginStoryboard >
                                        <Storyboard >
                                            <DoubleAnimation RepeatBehavior="Forever" Storyboard.TargetName="TransFIcon" 
                                         Storyboard.TargetProperty="Angle" To="0" Duration="0"/>
                                        </Storyboard>
                                    </BeginStoryboard>
                                </Trigger.ExitActions>
                            </Trigger>
                            <!--非激活状态-->
                            <Trigger Property="IsActive" Value="false">
                                <Setter Property="Visibility" Value="Collapsed" TargetName="FIcon"/>
                            </Trigger>
                        </ControlTemplate.Triggers>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    复制代码

      使用示例:  

                <CheckBox VerticalAlignment="Center" x:Name="cbActive2" IsChecked="True" Margin="5">IsActive</CheckBox>
                <core:BusyBox Width="80" Height="80" Foreground="White" Background="Red"  Margin="5"  IsActive="{Binding IsChecked ,ElementName=cbActive2}" />
                <core:BusyBox Width="30" Height="30" Foreground="White" Background="Red"  Margin="5"  IsActive="{Binding IsChecked ,ElementName=cbActive2}" />

    三.Win8/win10效果忙碌状态控件ProgressRing

      这是网上一个开源项目里的控件,项目地址:http://mahapps.com/。不做多介绍了,效果图:

     

      后台C#代码:  

    复制代码
        [TemplateVisualState(Name = "Large", GroupName = "SizeStates")]
        [TemplateVisualState(Name = "Small", GroupName = "SizeStates")]
        [TemplateVisualState(Name = "Inactive", GroupName = "ActiveStates")]
        [TemplateVisualState(Name = "Active", GroupName = "ActiveStates")]
        public class ProgressRing : Control
        {
            public static readonly DependencyProperty BindableWidthProperty = DependencyProperty.Register("BindableWidth", typeof(double), typeof(ProgressRing), new PropertyMetadata(default(double), BindableWidthCallback));
    
            public static readonly DependencyProperty IsActiveProperty = DependencyProperty.Register("IsActive", typeof(bool), typeof(ProgressRing), new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, IsActiveChanged));
    
            public static readonly DependencyProperty IsLargeProperty = DependencyProperty.Register("IsLarge", typeof(bool), typeof(ProgressRing), new PropertyMetadata(true, IsLargeChangedCallback));
    
            public static readonly DependencyProperty MaxSideLengthProperty = DependencyProperty.Register("MaxSideLength", typeof(double), typeof(ProgressRing), new PropertyMetadata(default(double)));
    
            public static readonly DependencyProperty EllipseDiameterProperty = DependencyProperty.Register("EllipseDiameter", typeof(double), typeof(ProgressRing), new PropertyMetadata(default(double)));
    
            public static readonly DependencyProperty EllipseOffsetProperty = DependencyProperty.Register("EllipseOffset", typeof(Thickness), typeof(ProgressRing), new PropertyMetadata(default(Thickness)));
    
            private List<Action> _deferredActions = new List<Action>();
    
            static ProgressRing()
            {
                DefaultStyleKeyProperty.OverrideMetadata(typeof(ProgressRing), new FrameworkPropertyMetadata(typeof(ProgressRing)));
                VisibilityProperty.OverrideMetadata(typeof(ProgressRing),
                                                    new FrameworkPropertyMetadata(
                                                        new PropertyChangedCallback(
                                                            (ringObject, e) =>
                                                            {
                                                                if (e.NewValue != e.OldValue)
                                                                {
                                                                    var ring = (ProgressRing)ringObject;
                                                                    //auto set IsActive to false if we're hiding it.
                                                                    if ((Visibility)e.NewValue != Visibility.Visible)
                                                                    {
                                                                        //sets the value without overriding it's binding (if any).
                                                                        ring.SetCurrentValue(ProgressRing.IsActiveProperty, false);
                                                                    }
                                                                    else
                                                                    {
                                                                        // #1105 don't forget to re-activate
                                                                        ring.IsActive = true;
                                                                    }
                                                                }
                                                            })));
            }
    
            public ProgressRing()
            {
                SizeChanged += OnSizeChanged;
            }
    
            public double MaxSideLength
            {
                get { return (double)GetValue(MaxSideLengthProperty); }
                private set { SetValue(MaxSideLengthProperty, value); }
            }
    
            public double EllipseDiameter
            {
                get { return (double)GetValue(EllipseDiameterProperty); }
                private set { SetValue(EllipseDiameterProperty, value); }
            }
    
            public Thickness EllipseOffset
            {
                get { return (Thickness)GetValue(EllipseOffsetProperty); }
                private set { SetValue(EllipseOffsetProperty, value); }
            }
    
            public double BindableWidth
            {
                get { return (double)GetValue(BindableWidthProperty); }
                private set { SetValue(BindableWidthProperty, value); }
            }
    
            public bool IsActive
            {
                get { return (bool)GetValue(IsActiveProperty); }
                set { SetValue(IsActiveProperty, value); }
            }
    
            public bool IsLarge
            {
                get { return (bool)GetValue(IsLargeProperty); }
                set { SetValue(IsLargeProperty, value); }
            }
    
            private static void BindableWidthCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                var ring = dependencyObject as ProgressRing;
                if (ring == null)
                    return;
    
                var action = new Action(() =>
                {
                    ring.SetEllipseDiameter(
                        (double)dependencyPropertyChangedEventArgs.NewValue);
                    ring.SetEllipseOffset(
                        (double)dependencyPropertyChangedEventArgs.NewValue);
                    ring.SetMaxSideLength(
                        (double)dependencyPropertyChangedEventArgs.NewValue);
                });
    
                if (ring._deferredActions != null)
                    ring._deferredActions.Add(action);
                else
                    action();
            }
    
            private void SetMaxSideLength(double width)
            {
                MaxSideLength = width <= 20 ? 20 : width;
            }
    
            private void SetEllipseDiameter(double width)
            {
                EllipseDiameter = width / 8;
            }
    
            private void SetEllipseOffset(double width)
            {
                EllipseOffset = new Thickness(0, width / 2, 0, 0);
            }
    
            private static void IsLargeChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                var ring = dependencyObject as ProgressRing;
                if (ring == null)
                    return;
    
                ring.UpdateLargeState();
            }
    
            private void UpdateLargeState()
            {
                Action action;
    
                if (IsLarge)
                    action = () => VisualStateManager.GoToState(this, "Large", true);
                else
                    action = () => VisualStateManager.GoToState(this, "Small", true);
    
                if (_deferredActions != null)
                    _deferredActions.Add(action);
    
                else
                    action();
            }
    
            private void OnSizeChanged(object sender, SizeChangedEventArgs sizeChangedEventArgs)
            {
                BindableWidth = ActualWidth;
            }
    
            private static void IsActiveChanged(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
            {
                var ring = dependencyObject as ProgressRing;
                if (ring == null)
                    return;
    
                ring.UpdateActiveState();
            }
    
            private void UpdateActiveState()
            {
                Action action;
    
                if (IsActive)
                    action = () => VisualStateManager.GoToState(this, "Active", true);
                else
                    action = () => VisualStateManager.GoToState(this, "Inactive", true);
    
                if (_deferredActions != null)
                    _deferredActions.Add(action);
    
                else
                    action();
            }
    
            public override void OnApplyTemplate()
            {
                //make sure the states get updated
                UpdateLargeState();
                UpdateActiveState();
                base.OnApplyTemplate();
                if (_deferredActions != null)
                    foreach (var action in _deferredActions)
                        action();
                _deferredActions = null;
            }
        }
    
        internal class WidthToMaxSideLengthConverter : IValueConverter
        {
            public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
            {
                if (value is double)
                {
                    var width = (double)value;
                    return width <= 20 ? 20 : width;
                }
    
                return null;
            }
    
            public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
            {
                throw new NotImplementedException();
            }
        }
    复制代码

      样式代码:  

    复制代码
        <Style TargetType="local:ProgressRing">
            <Setter Property="Foreground" Value="White" />
            <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="Height" Value="60" />
            <Setter Property="Width" Value="60" />
            <Setter Property="IsTabStop" Value="False" />
            <Setter Property="Template">
                <Setter.Value>
                    <ControlTemplate TargetType="local:ProgressRing">
                        <Border 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"
                                  Margin="{TemplateBinding Padding}"
                                  MaxWidth="{Binding MaxSideLength, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                  MaxHeight="{Binding MaxSideLength, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                  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 EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Margin="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             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 EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Margin="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             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 EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Margin="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             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 EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Margin="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             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 EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Margin="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             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 EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Height="{Binding EllipseDiameter, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Margin="{Binding EllipseOffset, RelativeSource={RelativeSource Mode=TemplatedParent}}"
                                             Fill="{TemplateBinding Foreground}" />
                                </Canvas>
                            </Grid>
                        </Border>
                    </ControlTemplate>
                </Setter.Value>
            </Setter>
        </Style>
    复制代码

    使用示例:  

                <CheckBox VerticalAlignment="Center" x:Name="cbActive" Margin="5" IsChecked="True">IsActive</CheckBox>
                <core:ProgressRing Width="80" Height="80" Foreground="Red" Margin="5"  IsActive="{Binding IsChecked ,ElementName=cbActive}" />

    四.弹出异步等待框WaitingBox

      效果图:

     

      使用的是一个模式窗体,异步执行传入的操作,实现的比较简单,没有做异常处理。另外一个缺陷就是没有支持取消操作。后台C#代码:  

    复制代码
       /// <summary>
        /// 简单等待框
        /// </summary>
        public partial class WaitingBox : Window
        {
            public string Text { get { return this.txtMessage.Text; } set { this.txtMessage.Text = value; } }
    
            private Action _Callback;
    
            public WaitingBox(Action callback)
            {
                InitializeComponent();
                this._Callback = callback;
                this.Loaded += WaitingBox_Loaded;
            }
    
            void WaitingBox_Loaded(object sender, RoutedEventArgs e)
            {
                this._Callback.BeginInvoke(this.OnComplate, null);
            }
    
            private void OnComplate(IAsyncResult ar)
            {
                this.Dispatcher.Invoke(new Action(() =>
                {
                    this.Close();
                }));
            }
            /// <summary>
            /// 显示等待框,owner指定宿主视图元素,callback为需要执行的方法体(需要自己做异常处理)。
            /// 目前等等框为模式窗体
            /// </summary>
            public static void Show(FrameworkElement owner, Action callback, string mes = "有一种幸福,叫做等待...")
            {
                WaitingBox win = new WaitingBox(callback);
                Window pwin = Window.GetWindow(owner);
                win.Owner = pwin;
                win.Text = mes;
                var loc = owner.PointToScreen(new Point());
                win.Left = loc.X + (owner.ActualWidth - win.Width) / 2;
                win.Top = loc.Y + (owner.ActualHeight - win.Height) / 2;
                win.ShowDialog();
            }
        }
    复制代码

      样式代码:  

    复制代码
    <Window x:Class="System.Windows.WaitingBox" x:Name="wb"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
            AllowsTransparency="True" WindowStyle="None" WindowStartupLocation="Manual"
            ShowInTaskbar="False" Background="Transparent"
            Title="WaitingBox" Height="110" Width="260">
        <Grid>
            <!--Background="{Binding Path=Background,ElementName=wb}"-->
            <Border Background="{StaticResource WaitingBoxBackground}"  Opacity="0.89" CornerRadius="1" Effect="{StaticResource WindowDropShadow}"></Border>
            <StackPanel VerticalAlignment="Center"  Orientation="Horizontal" HorizontalAlignment="Center" Margin="5">
                <TextBlock Text="&#xe65f;" x:Name="FIcon" FontSize="50" Style="{StaticResource FIcon}"  RenderTransformOrigin="0.5,0.5" Margin="3">
                    <TextBlock.RenderTransform>
                        <RotateTransform x:Name="TransFIcon" Angle="0"/>
                    </TextBlock.RenderTransform>
                </TextBlock>
                <TextBlock x:Name="txtMessage" Margin="2,10,15,10" Width="160" VerticalAlignment="Center" TextWrapping="Wrap">Loading...</TextBlock>
            </StackPanel>
        </Grid>
        <Window.Triggers>
            <EventTrigger RoutedEvent="Window.Loaded">
                <BeginStoryboard >
                    <Storyboard >
                        <DoubleAnimation RepeatBehavior="Forever" Storyboard.TargetName="TransFIcon" 
                                         Storyboard.TargetProperty="Angle" To="360" Duration="0:0:2.5"/>
                    </Storyboard>
                </BeginStoryboard>
            </EventTrigger>
        </Window.Triggers>
    </Window>
    复制代码

      使用比较简单,示例:  

                WaitingBox.Show(this, () =>
                {
                    System.Threading.Thread.Sleep(3000);
                },"正在玩命的加载,请稍后...");
                var res = MessageBoxX.Question("已经完了?");

    附录:参考引用 

    WPF自定义控件与样式(1)-矢量字体图标(iconfont)

    WPF自定义控件与样式(2)-自定义按钮FButton

    WPF自定义控件与样式(3)-TextBox & RichTextBox & PasswordBox样式、水印、Label标签、功能扩展

    WPF自定义控件与样式(4)-CheckBox/RadioButton自定义样式

    WPF自定义控件与样式(5)-Calendar/DatePicker日期控件自定义样式及扩展

    WPF自定义控件与样式(6)-ScrollViewer与ListBox自定义样式

    WPF自定义控件与样式(7)-列表控件DataGrid与ListView自定义样式

    WPF自定义控件与样式(8)-ComboBox与自定义多选控件MultComboBox

    WPF自定义控件与样式(9)-树控件TreeView与菜单Menu-ContextMenu

    WPF自定义控件与样式(10)-进度控件ProcessBar自定义样

    版权所有,文章来源:http://www.cnblogs.com/anding

  • 相关阅读:
    python链家网高并发异步爬虫and异步存入数据
    python爬取百度文库所有内容
    PyQt5+requests实现车票查询工具
    python黑科技库:FuckIt.py,让你代码从此远离bug
    教你如何使用Python写游戏辅助脚本
    python实现定时发送qq消息
    Python利用带权重随机数解决抽奖和游戏爆装备问题
    Beta冲刺随笔集合
    用户调查报告
    Beta冲刺总结
  • 原文地址:https://www.cnblogs.com/ljdong7/p/12115233.html
Copyright © 2011-2022 走看看