WPF实现转圈进度条效果

界面效果


在这里插入图片描述

  1. 控件界面
<UserControl x:Class="ProgressBarControl" 
       xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
       xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
       xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"  
       xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
       mc:Ignorable="d" d:DesignHeight="200" d:DesignWidth="300"
       Background="Gray" Loaded="ProgressBarControl_OnLoaded">

  <Grid>
    <Grid.Resources>
      <Style TargetType="Ellipse">
        <Setter Property="Height" Value="{Binding EclipseSize}"></Setter>
        <Setter Property="Width" Value="{Binding EclipseSize}"></Setter>
        <Setter Property="Stretch" Value="Fill"></Setter>
        <!--设置圆的颜色-->
        <Setter Property="Fill" Value="White"></Setter>
      </Style>
    </Grid.Resources>
    <StackPanel  HorizontalAlignment="Center" 
      VerticalAlignment="Center">
      <Viewbox Width="{Binding ViewBoxSize}" Height="{Binding ViewBoxSize}" 
      HorizontalAlignment="Center" 
      VerticalAlignment="Center">
        <Grid x:Name="LayoutRoot"  
        Background="Transparent" 
        HorizontalAlignment="Center" 
        VerticalAlignment="Center">
          <!--此处有canvas的加载和卸载事件-->
          <Canvas x:Name="ProgressBarCanvas" RenderTransformOrigin="0.5,0.5" 
          HorizontalAlignment="Center" 
          VerticalAlignment="Center" Width="{Binding CanvasSize}" 
          Height="{Binding CanvasSize}" Loaded="HandleLoaded" 
          Unloaded="HandleUnloaded" >
            <!--画圆-->            
            <Canvas.RenderTransform>
              <RotateTransform x:Name="SpinnerRotate" Angle="0" />
            </Canvas.RenderTransform>
          </Canvas>
        </Grid>
      </Viewbox>
    </StackPanel>
  </Grid>
</UserControl> 
  1. 控件后台逻辑
/// <summary>
  /// 进度条
  /// </summary>
  public partial class ProgressBarControl : UserControl
  {
    //集成到按指定时间间隔和指定优先级处理的 System.Windows.Threading.Dispatcher 队列中的计时器。
    private DispatcherTimer animationTimer;
    private ProgressBarDataModel _dataModel;
    private int index = 0;
    #region 构造方法与加载
    /// <summary>
    /// 构造方法
    /// </summary>
    public ProgressBarControl()
    {
      InitializeComponent();
      
    }
    /// <summary>
    /// 加载后刷新
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void ProgressBarControl_OnLoaded(object sender, RoutedEventArgs e)
    {
      animationTimer = new DispatcherTimer(DispatcherPriority.ContextIdle, Dispatcher);
      //指定时间间隔
      animationTimer.Interval = new TimeSpan(0, 0, 0, 0, TimeSpan);
      if (EllipseCount < 1)
      {
        EllipseCount = 12;
      }
      for (int i = 0; i < EllipseCount; i++)
      {
        ProgressBarCanvas.Children.Add(new Ellipse());
      }
      var dataModel = new ProgressBarDataModel()
      {
        CanvasSize = CanvasSize,
        EclipseSize = EllipseSize
      };
      _dataModel = dataModel;
      this.DataContext = dataModel;
    }
    #endregion

    #region 属性
    /// <summary>
    /// 获取或设置圆圈数量
    /// 默认12
    /// </summary>
    public double EllipseCount
    {
      get { return (double)GetValue(EllipseCountProperty); }
      set { SetValue(EllipseCountProperty, value); }
    }
    public static readonly DependencyProperty EllipseCountProperty =
      DependencyProperty.Register("EllipseCount", typeof(double), typeof(ProgressBarControl),
      new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender));

    /// <summary>
    /// 获取或设置圆圈大小
    /// 默认10
    /// </summary>
    public double EllipseSize
    {
      get { return (double)GetValue(EllipseSizeProperty); }
      set { SetValue(EllipseSizeProperty, value); }
    }
    public static readonly DependencyProperty EllipseSizeProperty =
      DependencyProperty.Register("EllipseSize", typeof(double), typeof(ProgressBarControl),
      new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender));

    /// <summary>
    /// 获取或设置面板大小
    /// 默认80
    /// </summary>
    public double CanvasSize
    {
      get { return (double)GetValue(CanvasSizeProperty); }
      set { SetValue(CanvasSizeProperty, value); }
    }
    public static readonly DependencyProperty CanvasSizeProperty =
      DependencyProperty.Register("CanvasSize", typeof(double), typeof(ProgressBarControl),
      new FrameworkPropertyMetadata(80.0, FrameworkPropertyMetadataOptions.AffectsRender));

    /// <summary>
    /// 获取或设置每次旋转角度
    /// 默认10.0
    /// </summary>
    public double StepAngle
    {
      get { return (double)GetValue(StepAngleProperty); }
      set { SetValue(StepAngleProperty, value); }
    }

    public static readonly DependencyProperty StepAngleProperty =
      DependencyProperty.Register("StepAngle", typeof(double), typeof(ProgressBarControl),
      new FrameworkPropertyMetadata(10.0, FrameworkPropertyMetadataOptions.AffectsRender));
    /// <summary>
    /// 获取或设置每次旋转间隔时间(毫秒)
    /// 默认100毫秒
    /// </summary>
    public int TimeSpan
    {
      get { return (int)GetValue(TimeSpanProperty); }
      set { SetValue(TimeSpanProperty, value); }
    }
    public static readonly DependencyProperty TimeSpanProperty =
      DependencyProperty.Register("TimeSpan", typeof(int), typeof(ProgressBarControl),
      new FrameworkPropertyMetadata(100, FrameworkPropertyMetadataOptions.AffectsRender));
    
    #endregion

    #region 方法
    /// <summary>
    /// Canvas加载
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void HandleLoaded(object sender, RoutedEventArgs e)
    {
      //设置设置圆的位置和旋转角度
      SetEclipsePosition(_dataModel);
      //DesignerProperties  提供用于与设计器进行通信的附加属性。
      if (!DesignerProperties.GetIsInDesignMode(this))
      {
        if (this.Visibility == System.Windows.Visibility.Visible)
        {
          //超过计时器间隔时发生。
          animationTimer.Tick += HandleAnimationTick;
          animationTimer.Start();
        }
      }
    }

    /// <summary>
    /// 设置圆的位置和旋转角度
    /// </summary>
    private void SetEclipsePosition(ProgressBarDataModel dataModel)
    {
      //圆周长就是:C = π * d 或者C=2*π*r(其中d是圆的直径,r是圆的半径)
      double r =dataModel.R;

      var children=ProgressBarCanvas.Children;
      int count = children.Count;
      double step = (Math.PI * 2) / count;

      //根据圆中正弦、余弦计算距离
      int index = 0;
      foreach (var element in children)
      {
        var ellipse = element as Ellipse;
        //透明度
        var opacity = Convert.ToDouble(index)/(count - 1);
        ellipse.SetValue(UIElement.OpacityProperty, opacity<0.05?0.05:opacity);
        //距离
        double left = r + Math.Sin(step*index)*r;
        ellipse.SetValue(Canvas.LeftProperty,left);
        double top = r - Math.Cos(step*index)*r;
        ellipse.SetValue(Canvas.TopProperty, top);

        index++;
      }
    }

    /// <summary>
    /// Canvas卸载时
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void HandleUnloaded(object sender, RoutedEventArgs e)
    {
      animationTimer.Stop();
      //除去委托
      animationTimer.Tick -= HandleAnimationTick;
    }

    /// <summary>
    /// 超过计时器间隔时发生。
    /// </summary>
    /// <param name="sender"></param>
    /// <param name="e"></param>
    private void HandleAnimationTick(object sender, EventArgs e)
    {
      //设置旋转角度
      SpinnerRotate.Angle = (SpinnerRotate.Angle + StepAngle) % 360;
    }
    #endregion
}
  1. ViewModel
/// <summary>
  /// 进度条Model类
  /// </summary>
  public class ProgressBarDataModel
  {
    public double EclipseSize { get; set; }
    public double CanvasSize { get; set; }
    public double ViewBoxSize
    {
      get
      {
        double length = Convert.ToDouble(CanvasSize) - Convert.ToDouble(EclipseSize);
        return length;
      }
    }
    public double EclipseLeftLength
    {
      get
      {
        double length = Convert.ToDouble(CanvasSize) / 2;
        return length;
      }
    }
    public double R
    {
      get
      {
        double length = (Convert.ToDouble(CanvasSize) - Convert.ToDouble(EclipseSize)) / 2;
        return length;
      }
    }
}
  1. 使用
<control:ProgressBarControl CanvasSize="100" EllipseCount="10" EllipseSize="10" StepAngle="36" TimeSpan="60"/>
Task.Run(() =>
            {
                Thread.Sleep(1000);
                Application.Current.Dispatcher.Invoke(() =>
                
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: WPF环形虚线进度条是一种以圆形形式展示进度的控件。在WPF中,可以使用Ellipse(椭圆)和Path(路径)来创建环形虚线效果。 首先,我们可以在XAML中添加一个Ellipse元素作为背景圆形,并设置其宽度、高度、填充颜色等属性来定义进度条的样式。 接着,我们可以使用Path元素来创建环形虚线效果。虚线的形状可以通过设置路径数据来定义。例如,可以使用LineSegment(线段)和ArcSegment(弧段)来绘制虚线的路径。 然后,使用DoubleAnimation进行动画效果实现。可以通过设置动画的起始值和结束值来控制进度条的动态变化。通过设置动画的插值函数,可以使进度条以流畅的方式过渡。 最后,在代码中可以根据实际需要来更新进度条的值,从而实现进度的动态显示。可以通过通过绑定ProgressBar或者自定义一个依赖属性来实现。 总之,WPF环形虚线进度条可以通过控制Ellipse和Path元素的样式、动画以及数值来实现。这种形式的进度条可以提供更加直观的用户体验,让用户清晰地了解任务的进展情况。 ### 回答2: WPF环形虚线进度条是一种用于展示进度的界面元素,其外观呈现环形,并且线条是虚线的效果。以下是实现效果的方法: 首先,我们需要使用WPF的布局容器来创建一个环形的背景,并将其设置为透明。可以使用Canvas或Grid等容器来实现此目的。 其次,在环形背景上,我们可以使用Path元素来绘制虚线。Path元素可以使用Geometry绘制各种形状,包括虚线。我们可以使用LineGeometry来绘制一条直线,并设置其Stroke属性为虚线样式。 然后,我们可以使用Storyboard动画来控制虚线的显示进度。可以使用DoubleAnimation来控制虚线的起始和结束点,从而实现进度的动画效果。可以根据实际需求调整动画的速度、重复次数等属性。 最后,我们可以根据进度条的值来控制动画的触发。可以使用数据绑定将进度条的值绑定到动画的开始和结束点上,从而实现进度条随数据变化而更新动画进度。 总结来说,实现WPF环形虚线进度条需要使用布局容器、Path元素、动画和数据绑定等技术。通过合理设置这些组件的属性和关联关系,我们可以实现一个漂亮而实用的环形虚线进度条。 ### 回答3: WPF环形虚线进度条是一种在WPF应用程序中展示进度的视觉元素。它通常用于表示某个操作的完成程度或加载进度。环形虚线进度条具有以下特点: 1. 外观:环形虚线进度条呈现为一个圆环,通过一系列由虚线组成的元素来表示进度。它的背景可以是透明的或者设置为特定的颜色。 2. 进度显示:进度条上的虚线根据当前的操作进度进行显示。随着操作进展,虚线的数量和位置会发生变化,以反映出当前的进度。 3. 自定义:WPF环形虚线进度条可以通过样式和模板来进行自定义。可以调整虚线的样式、颜色、厚度等属性,以满足不同的设计需求。 4. 动画效果:在操作进行过程中,环形虚线进度条通常会配合动画效果,如旋转或者渐变变化。这样可以增加进度条的交互性和视觉吸引力。 使用WPF环形虚线进度条可以使用户更直观地了解操作的进度,提高用户体验。它适用于各种需要展示进度的应用场景,如文件上传、下载、数据处理等。通过合理设计,并结合其他视觉元素,可以使环形虚线进度条更加美观和有效地传达进度信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值