WPF中利用Ellipse或Rectangle实现圆形进度条

效果如下
在这里插入图片描述
上面两个进度条,分别利用了Ellipse或Rectangle的StrokeThickness属性和StrokeDashArray属性,StrokeDashArray是设置边框长度,但要根据StrokeThickness的厚度进行相关于周长的转换。
转换函数如下

/// <summary>
/// 计算进度条百分比
/// </summary>
/// <param name="progress">百分比0-100</param>
/// <param name="radius">圆角的度数</param>
/// <param name="thickness">控件边框厚度</param>
/// <returns></returns>
public static DoubleCollection CalcProgress(double progress, double radius,double thickness)
{
    var r = radius - thickness / 2;
    var perimeter = 2 * Math.PI * r / thickness;
    var step = progress / 100 * perimeter;
    var result = new DoubleCollection() { step, 1000 };
    return result;
}

下面分别是Ellipse或Rectangle实现的圆形进度条的UI代码

<StackPanel Background="#4E59A4" Orientation="Horizontal">
	 <Grid Margin="50" Background="Transparent" Width="100" Height="100">
	     <Ellipse Stroke="Gray" StrokeThickness="12"/>
	     <Ellipse StrokeThickness="12" StrokeDashArray="{Binding ProcessValue}" RenderTransformOrigin="0.5,0.5">
	         <Ellipse.Stroke>
	             <LinearGradientBrush StartPoint="0.5,0.5" EndPoint="0,1">
	                 <GradientStop Offset="1" Color="#B7A227"/>
	                 <GradientStop Offset="0" Color="#0a9644"/>
	             </LinearGradientBrush>
	         </Ellipse.Stroke>
	         <Ellipse.Effect>
	             <DropShadowEffect BlurRadius="8" ShadowDepth="0" Opacity="1" Color="WhiteSmoke"/>
	         </Ellipse.Effect>
	         <Ellipse.RenderTransform>
	             <RotateTransform Angle="-90"/>
	         </Ellipse.RenderTransform>
	     </Ellipse>
	     <TextBlock Foreground="White" Text="{Binding ProcessNumber}" FontSize="25" HorizontalAlignment="Center" VerticalAlignment="Center">
	         <TextBlock.Effect>
	             <DropShadowEffect ShadowDepth="0" BlurRadius="6" Color="White"/>
	         </TextBlock.Effect>
	     </TextBlock>
	 </Grid>
	
	 <Grid Margin="50" Background="Transparent" Width="100" Height="100">
	     <Rectangle Width="100" Height="100" Stroke="LightGray" StrokeThickness="12" RadiusX="50" RadiusY="50"/>
	     <Rectangle Width="100" Height="100" StrokeThickness="12" RadiusX="50" RadiusY="50" StrokeDashCap="Round" StrokeDashArray="{Binding ProcessValue}"  RenderTransformOrigin="0.5,0.5">
	         <Rectangle.Stroke>
	             <LinearGradientBrush StartPoint="0.5,0.5" EndPoint="0,1">
	                 <GradientStop Offset="1" Color="#FFCD41"/>
	                 <GradientStop Offset="0" Color="#0a9644"/>
	             </LinearGradientBrush>
	         </Rectangle.Stroke>
	         <Rectangle.Effect>
	             <DropShadowEffect BlurRadius="8" ShadowDepth="0" Opacity="1" Color="WhiteSmoke"/>
	         </Rectangle.Effect>
	         <Rectangle.RenderTransform>
	             <RotateTransform Angle="90"/>
	         </Rectangle.RenderTransform>
	     </Rectangle>
	     <TextBlock Foreground="White" Text="{Binding ProcessNumber}" FontSize="25" HorizontalAlignment="Center" VerticalAlignment="Center">
	         <TextBlock.Effect>
	             <DropShadowEffect ShadowDepth="0" BlurRadius="6" Color="White"/>
	         </TextBlock.Effect>
	     </TextBlock>
	 </Grid>
	</StackPanel>

这里我们主要是绑定了一个ProcessValue对象给到Ellipse或Rectangle的StrokeDashArray属性,而ProcessValue对象是一个DoubleCollection类,它表示 System.Double 值的有序集合。最后我们在一个适当的地方更新ProcessValue的值即可。

Task.Run(() =>
{
    while (true)
    {
        Thread.Sleep(1000);
        Application.Current.Dispatcher.Invoke(() =>
        {
            double second = (DateTime.Now.Second * 100) / 60;
            ProcessValue = CalcHelper.CalcProgress(second, 50, 12);
            ProcessNumber = second + "%";
        });

    }
});

下面是两个绑定属性的定义

private DoubleCollection doubleCollection = new DoubleCollection() { 0, 1000 };
/// <summary>
/// 圆形进度条数组
/// </summary>
public DoubleCollection ProcessValue
{
    get { return doubleCollection; }
    set { doubleCollection = value;RaisePropertyChanged("ProcessValue"); }
}

private string processNumber;
/// <summary>
/// 圆形进度条百分比值
/// </summary>
public string ProcessNumber
{
    get { return processNumber; }
    set { processNumber = value; RaisePropertyChanged("ProcessNumber"); }
}
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我会尽力回答你的问题。 首先,MVVM框架是一种用于构建WPF应用程序的设计模式,它将应用程序分为三个部分:模型(Model)、视图(View)和视图模型(ViewModel)。模型是应用程序的数据和业务逻辑,视图是用户界面,而视图模型是连接模型和视图的介。 接下来,我们来实现鼠标操作画圆和旋转矩形的功能。首先,在视图模型创建两个命令,一个用于画圆,一个用于旋转矩形。在命令的Execute方法,我们可以通过鼠标事件获取到鼠标的位置,然后根据这个位置绘制圆或者矩形。 下面是一个简单的示例代码: ```csharp public class MainViewModel : INotifyPropertyChanged { public ICommand DrawCircleCommand { get; set; } public ICommand RotateRectangleCommand { get; set; } private Point _lastPosition; private ObservableCollection<Shape> _shapes = new ObservableCollection<Shape>(); public ObservableCollection<Shape> Shapes { get { return _shapes; } set { _shapes = value; OnPropertyChanged(nameof(Shapes)); } } public MainViewModel() { DrawCircleCommand = new RelayCommand(DrawCircle); RotateRectangleCommand = new RelayCommand(RotateRectangle); } private void DrawCircle(object obj) { var args = obj as MouseEventArgs; if (args != null) { var position = args.GetPosition(null); var radius = 50; var circle = new Ellipse { Width = radius, Height = radius, Fill = Brushes.Red }; Canvas.SetLeft(circle, position.X - radius / 2); Canvas.SetTop(circle, position.Y - radius / 2); Shapes.Add(circle); } } private void RotateRectangle(object obj) { var args = obj as MouseEventArgs; if (args != null) { var position = args.GetPosition(null); var width = 100; var height = 50; var rectangle = new Rectangle { Width = width, Height = height, Fill = Brushes.Green, RenderTransformOrigin = new Point(0.5, 0.5) }; Canvas.SetLeft(rectangle, position.X - width / 2); Canvas.SetTop(rectangle, position.Y - height / 2); var transform = new RotateTransform { Angle = 0 }; rectangle.RenderTransform = transform; Shapes.Add(rectangle); var animation = new DoubleAnimation { From = 0, To = 360, Duration = new Duration(TimeSpan.FromSeconds(5)), RepeatBehavior = RepeatBehavior.Forever }; transform.BeginAnimation(RotateTransform.AngleProperty, animation); } } public event PropertyChangedEventHandler PropertyChanged; protected void OnPropertyChanged(string propertyName) { PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); } } public class RelayCommand : ICommand { private Action<object> _execute; private Func<object, bool> _canExecute; public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null) { _execute = execute; _canExecute = canExecute; } public bool CanExecute(object parameter) { return _canExecute == null || _canExecute(parameter); } public void Execute(object parameter) { _execute(parameter); } public event EventHandler CanExecuteChanged; public void RaiseCanExecuteChanged() { CanExecuteChanged?.Invoke(this, EventArgs.Empty); } } ``` 在这个示例代码,我们创建了一个MainViewModel类,其包含了两个命令DrawCircleCommand和RotateRectangleCommand,分别用于绘制圆和旋转矩形。当用户在画布上单击鼠标时,会触发对应的命令,并通过鼠标事件获取到鼠标位置,然后创建相应的形状并添加到Shapes集合。可以通过绑定Shapes集合到画布上,将绘制的形状显示在界面上。 以上是一个简单的实现,具体的实现方式可以根据自己的需求进行调整和优化。希望能对你有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值