如何创建自定义进度条,最小值为0,从左下角开始?

huangapple go评论58阅读模式
英文:

How to create Custom progress bar minimum value 0 starts from the bottom left corner?

问题

我想要将进度条的起始点设为0%,结束点设为100%,并放置在左下角。并且希望数值的变化能够正常显示。我该如何实现?

我希望进度条的数值在圆形上增加和减少。

我的测试结果不正确,我不知道问题出在哪里以及如何解决它。

Xaml:

<!-- 代码省略 -->

Codebehind:

// 代码省略

结果:

如何创建自定义进度条,最小值为0,从左下角开始?

编辑:

如何创建自定义进度条,最小值为0,从左下角开始?

更新:

我如何通过拖动球来改变进度值?

<!-- 代码省略 -->

如何创建自定义进度条,最小值为0,从左下角开始?

英文:

I want the starting point 0% and the ending point 100% of the progress bar to be in the lower left corner. And the progress of the value changes to display normally. How can I accomplish it?

I want the progress bar to increase and decrease in value along the circle.

The result of my test is not correct, I don't know where is the problem and how to fix it.

Xaml:

&lt;Window.Resources&gt;
&lt;local:AngleToPointConverter x:Key=&quot;prConverter&quot;/&gt;
&lt;local:AngleToIsLargeConverter x:Key=&quot;isLargeConverter&quot;/&gt;
&lt;Style x:Key=&quot;circularProgressBar&quot; TargetType=&quot;local:CircularProgressBar&quot;&gt;
&lt;Setter Property=&quot;Value&quot; Value=&quot;10&quot;/&gt;
&lt;Setter Property=&quot;Maximum&quot; Value=&quot;100&quot;/&gt;
&lt;Setter Property=&quot;StrokeThickness&quot; Value=&quot;10&quot;/&gt;
&lt;Setter Property=&quot;Template&quot;&gt;
&lt;Setter.Value&gt;
&lt;ControlTemplate TargetType=&quot;local:CircularProgressBar&quot;&gt;
&lt;Canvas Width=&quot;100&quot; Height=&quot;130&quot;&gt;
&lt;Ellipse Width=&quot;101&quot; Height=&quot;101&quot; Stroke=&quot;LightGray&quot; Opacity=&quot;0.7&quot; StrokeThickness=&quot;4&quot;  /&gt;
&lt;Path Stroke=&quot;{TemplateBinding Background}&quot; 
StrokeThickness=&quot;{TemplateBinding StrokeThickness}&quot;&gt;
&lt;Path.Data&gt;
&lt;PathGeometry&gt;
&lt;PathFigure x:Name=&quot;fig&quot; StartPoint=&quot;20,90&quot;&gt;
&lt;ArcSegment RotationAngle=&quot;0&quot; SweepDirection=&quot;Clockwise&quot;
Size=&quot;50,50&quot;
Point=&quot;{Binding Path=Angle, Converter={StaticResource prConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}&quot;
IsLargeArc=&quot;{Binding Path=Angle, Converter={StaticResource isLargeConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}&quot;
&gt;
&lt;/ArcSegment&gt;
&lt;/PathFigure&gt;
&lt;/PathGeometry&gt;
&lt;/Path.Data&gt;
&lt;/Path&gt;
&lt;Border Width=&quot;100&quot; Height=&quot;100&quot;&gt;
&lt;Grid&gt;
&lt;Ellipse Width=&quot;50&quot; Height=&quot;50&quot;   Fill=&quot;White&quot;  /&gt;
&lt;Image Width=&quot;20&quot; Height=&quot;20&quot; Margin=&quot;30,25,30,30&quot; Source=&quot;bulb1.PNG&quot;/&gt;
&lt;TextBlock Width=&quot;50&quot; Foreground=&quot;Black&quot; Height=&quot;20&quot;  Margin=&quot;10,40,10,5&quot; TextAlignment=&quot;Center&quot;
Text=&quot;{Binding Path=Value, StringFormat={}{0}%,  
RelativeSource={RelativeSource TemplatedParent}}&quot;
FontSize=&quot;{TemplateBinding FontSize}&quot;/&gt;
&lt;/Grid&gt;
&lt;/Border&gt;
&lt;Canvas  Canvas.Top=&quot;110&quot;&gt;
&lt;Button x:Name=&quot;decrease&quot;  Margin=&quot;20,0,0,0&quot; Command=&quot;{Binding DecreaseCommand}&quot; &gt;
&lt;Button.Style&gt;
&lt;Style TargetType=&quot;{x:Type Button}&quot;&gt;
&lt;Setter Property=&quot;Template&quot;&gt;
&lt;Setter.Value&gt;
&lt;ControlTemplate&gt;
&lt;Grid&gt;
&lt;Ellipse Width=&quot;20&quot; Height=&quot;20&quot; Stroke=&quot;LightGray&quot;  StrokeThickness=&quot;1&quot;  /&gt;
&lt;Border Width=&quot;20&quot; Height=&quot;20&quot; &gt;
&lt;TextBlock Foreground=&quot;LightGray&quot; Text=&quot;-&quot; FontWeight=&quot;Bold&quot; HorizontalAlignment=&quot;Center&quot; VerticalAlignment=&quot;Center&quot; /&gt;
&lt;/Border&gt;
&lt;/Grid&gt;
&lt;/ControlTemplate&gt;
&lt;/Setter.Value&gt;
&lt;/Setter&gt;
&lt;/Style&gt;
&lt;/Button.Style&gt;
&lt;/Button&gt;
&lt;Button x:Name=&quot;increase&quot;  Margin=&quot;60,0,0,0&quot; Grid.Column=&quot;1&quot; Command=&quot;{Binding IncreaseCommand}&quot; &gt;
&lt;Button.Style&gt;
&lt;Style TargetType=&quot;{x:Type Button}&quot;&gt;
&lt;Setter Property=&quot;Template&quot;&gt;
&lt;Setter.Value&gt;
&lt;ControlTemplate&gt;
&lt;Grid&gt;
&lt;Ellipse Width=&quot;20&quot; Height=&quot;20&quot; Stroke=&quot;LightGray&quot;  StrokeThickness=&quot;1&quot; /&gt;
&lt;Border Width=&quot;20&quot; Height=&quot;20&quot;   Grid.Column=&quot;1&quot;&gt;
&lt;TextBlock Foreground=&quot;LightGray&quot; Text=&quot;+&quot; FontWeight=&quot;Bold&quot;  VerticalAlignment=&quot;Center&quot; HorizontalAlignment=&quot;Center&quot; /&gt;
&lt;/Border&gt;
&lt;/Grid&gt;
&lt;/ControlTemplate&gt;
&lt;/Setter.Value&gt;
&lt;/Setter&gt;
&lt;/Style&gt;
&lt;/Button.Style&gt;
&lt;/Button&gt;
&lt;!--&lt;Ellipse Width=&quot;20&quot; Height=&quot;20&quot; Stroke=&quot;LightGray&quot;  StrokeThickness=&quot;1&quot;  Margin=&quot;20,0,0,0&quot;/&gt;
&lt;Border Width=&quot;20&quot; Height=&quot;20&quot; Margin=&quot;20,0,0,0&quot;&gt;
&lt;TextBlock Foreground=&quot;LightGray&quot; Text=&quot;-&quot; HorizontalAlignment=&quot;Center&quot; /&gt;
&lt;/Border&gt;
&lt;Ellipse Width=&quot;20&quot; Height=&quot;20&quot; Stroke=&quot;LightGray&quot;  StrokeThickness=&quot;1&quot;  Margin=&quot;60,0,0,0&quot;/&gt;
&lt;Border Width=&quot;20&quot; Height=&quot;20&quot; Margin=&quot;60,0,0,0&quot;&gt;
&lt;TextBlock Foreground=&quot;LightGray&quot; Text=&quot;+&quot; HorizontalAlignment=&quot;Center&quot; /&gt;
&lt;/Border&gt;--&gt;
&lt;/Canvas&gt;
&lt;/Canvas&gt;
&lt;/ControlTemplate&gt;
&lt;/Setter.Value&gt;
&lt;/Setter&gt;
&lt;/Style&gt;
&lt;/Window.Resources&gt;
&lt;Grid Background=&quot;DarkBlue&quot;&gt;
&lt;local:CircularProgressBar Background=&quot;White&quot; Style=&quot;{StaticResource  circularProgressBar }&quot;
Value=&quot;{Binding ElementName=CirularSlider, Path= Value}&quot;  Foreground=&quot;Black&quot; FontWeight=&quot;Bold&quot;
StrokeThickness=&quot;4&quot;  
BorderBrush=&quot;LightGray&quot;/&gt;
&lt;Slider Minimum=&quot;0&quot; Maximum=&quot;100&quot; 
x:Name=&quot;CirularSlider&quot; IsSnapToTickEnabled=&quot;True&quot;
VerticalAlignment=&quot;Top&quot; Value=&quot;10&quot;/&gt;
&lt;/Grid&gt;

Codebedhind:

public class CircularProgressBar : ProgressBar
{
public CircularProgressBar()
{
this.ValueChanged += CircularProgressBar_ValueChanged;
}
void CircularProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs&lt;double&gt; e)
{
CircularProgressBar bar = sender as CircularProgressBar;
double currentAngle = bar.Angle;
double targetAngle = e.NewValue / bar.Maximum * 359.999;
//  double targetAngle = e.NewValue / bar.Maximum * 179.999;
DoubleAnimation anim = new DoubleAnimation(currentAngle, targetAngle, TimeSpan.FromMilliseconds(500));
bar.BeginAnimation(CircularProgressBar.AngleProperty, anim, HandoffBehavior.SnapshotAndReplace);
}
public double Angle
{
get { return (double)GetValue(AngleProperty); }
set { SetValue(AngleProperty, value); }
}
// Using a DependencyProperty as the backing store for Angle.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty AngleProperty =
DependencyProperty.Register(&quot;Angle&quot;, typeof(double), typeof(CircularProgressBar), new PropertyMetadata(0.0));
public double StrokeThickness
{
get { return (double)GetValue(StrokeThicknessProperty); }
set { SetValue(StrokeThicknessProperty, value); }
}
// Using a DependencyProperty as the backing store for StrokeThickness.  This enables animation, styling, binding, etc...
public static readonly DependencyProperty StrokeThicknessProperty =
DependencyProperty.Register(&quot;StrokeThickness&quot;, typeof(double), typeof(CircularProgressBar), new PropertyMetadata(10.0));
}
public class AngleToPointConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double angle = (double)value;
double radius = 50;
double piang = angle * Math.PI / 180;
//double piang = angle * Math.PI / 310;
double px = Math.Sin(piang) * radius + radius;
double py = -Math.Cos(piang) * radius + radius;
return new System.Windows.Point(px, py);
}
public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class AngleToIsLargeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double angle = (double)value;
return angle &gt; 180;
// return angle &gt; 300;
}
public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

The result:
如何创建自定义进度条,最小值为0,从左下角开始?

Edit:

如何创建自定义进度条,最小值为0,从左下角开始?

Update:

How can I change the progress value by dragging the ball?

&lt;Style x:Key=&quot;circularProgressBar1&quot; TargetType=&quot;local:CircularProgressBar&quot;&gt;
&lt;Setter Property=&quot;Value&quot; Value=&quot;10&quot;/&gt;
&lt;Setter Property=&quot;Maximum&quot; Value=&quot;100&quot;/&gt;
&lt;Setter Property=&quot;StrokeThickness&quot; Value=&quot;7&quot;/&gt;
&lt;Setter Property=&quot;Template&quot;&gt;
&lt;Setter.Value&gt;
&lt;ControlTemplate TargetType=&quot;local:CircularProgressBar&quot;&gt;
&lt;Canvas Width=&quot;100&quot; Height=&quot;130&quot;&gt;
&lt;Ellipse Width=&quot;105&quot; Height=&quot;104&quot; Margin=&quot;-2.4,-1.5,0,0&quot; Stroke=&quot;LightGray&quot; Opacity=&quot;0.7&quot;  StrokeThickness=&quot;8&quot;  /&gt;
&lt;Path Stroke=&quot;{TemplateBinding Background}&quot;  StrokeStartLineCap=&quot;Round&quot; StrokeEndLineCap=&quot;Round&quot;
StrokeThickness=&quot;{TemplateBinding StrokeThickness}&quot;&gt;
&lt;Path.Data&gt;
&lt;PathGeometry&gt;
&lt;PathFigure x:Name=&quot;fig&quot; StartPoint=&quot;20,90&quot;&gt;
&lt;ArcSegment RotationAngle=&quot;0&quot; SweepDirection=&quot;Clockwise&quot; 
Size=&quot;50,50&quot;
Point=&quot;{Binding Path=Angle, Converter={StaticResource prConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}&quot;
IsLargeArc=&quot;{Binding Path=Angle, Converter={StaticResource isLargeConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}&quot;
&gt;
&lt;/ArcSegment&gt;
&lt;/PathFigure&gt;
&lt;/PathGeometry&gt;
&lt;/Path.Data&gt;
&lt;/Path&gt;
&lt;Button&gt;
&lt;Button.Style&gt;
&lt;Style TargetType=&quot;Button&quot;&gt;
&lt;Setter Property=&quot;Template&quot;&gt;
&lt;Setter.Value&gt;
&lt;ControlTemplate&gt;
&lt;Path Stroke=&quot;Black&quot; StrokeThickness=&quot;10&quot; StrokeStartLineCap=&quot;Round&quot; StrokeEndLineCap=&quot;Round&quot;&gt;
&lt;Path.Data&gt;
&lt;PathGeometry&gt;
&lt;PathGeometry.Figures&gt;
&lt;PathFigure StartPoint=&quot;{Binding Path=Angle, Converter={StaticResource prConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}&quot;&gt;
&lt;PathFigure.Segments&gt;
&lt;LineSegment Point=&quot;{Binding Path=Angle, Converter={StaticResource prConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}&quot; /&gt;
&lt;/PathFigure.Segments&gt;
&lt;/PathFigure&gt;
&lt;/PathGeometry.Figures&gt;
&lt;/PathGeometry&gt;
&lt;/Path.Data&gt;
&lt;/Path&gt;
&lt;/ControlTemplate&gt;
&lt;/Setter.Value&gt;
&lt;/Setter&gt;
&lt;/Style&gt;
&lt;/Button.Style&gt;
&lt;/Button&gt;
&lt;Border Width=&quot;100&quot; Height=&quot;100&quot;&gt;
&lt;Grid&gt;
&lt;Ellipse Width=&quot;50&quot; Height=&quot;50&quot;   Fill=&quot;White&quot;  /&gt;
&lt;Image Width=&quot;20&quot; Height=&quot;20&quot; Margin=&quot;30,25,30,30&quot; Source=&quot;bulb1.PNG&quot;/&gt;
&lt;TextBlock Width=&quot;50&quot; Foreground=&quot;Black&quot; Height=&quot;20&quot;  Margin=&quot;10,40,10,5&quot; TextAlignment=&quot;Center&quot;
Text=&quot;{Binding Path=Value, StringFormat={}{0}%,  
RelativeSource={RelativeSource TemplatedParent}}&quot;
FontSize=&quot;{TemplateBinding FontSize}&quot;/&gt;
&lt;/Grid&gt;
&lt;/Border&gt;
&lt;Canvas  Canvas.Top=&quot;110&quot;&gt;
&lt;Button x:Name=&quot;decrease&quot;  Margin=&quot;20,0,0,0&quot; Command=&quot;{Binding DecreaseCommand}&quot; &gt;
&lt;Button.Style&gt;
&lt;Style TargetType=&quot;{x:Type Button}&quot;&gt;
&lt;Setter Property=&quot;Template&quot;&gt;
&lt;Setter.Value&gt;
&lt;ControlTemplate&gt;
&lt;Grid&gt;
&lt;Ellipse Width=&quot;20&quot; Height=&quot;20&quot; Stroke=&quot;LightGray&quot;  StrokeThickness=&quot;1&quot;  /&gt;
&lt;Border Width=&quot;20&quot; Height=&quot;20&quot; &gt;
&lt;TextBlock Foreground=&quot;LightGray&quot; Text=&quot;-&quot; FontWeight=&quot;Bold&quot; HorizontalAlignment=&quot;Center&quot; VerticalAlignment=&quot;Center&quot; /&gt;
&lt;/Border&gt;
&lt;/Grid&gt;
&lt;/ControlTemplate&gt;
&lt;/Setter.Value&gt;
&lt;/Setter&gt;
&lt;/Style&gt;
&lt;/Button.Style&gt;
&lt;/Button&gt;
&lt;Button x:Name=&quot;increase&quot;  Margin=&quot;60,0,0,0&quot; Grid.Column=&quot;1&quot; Command=&quot;{Binding IncreaseCommand}&quot; &gt;
&lt;Button.Style&gt;
&lt;Style TargetType=&quot;{x:Type Button}&quot;&gt;
&lt;Setter Property=&quot;Template&quot;&gt;
&lt;Setter.Value&gt;
&lt;ControlTemplate&gt;
&lt;Grid&gt;
&lt;Ellipse Width=&quot;20&quot; Height=&quot;20&quot; Stroke=&quot;LightGray&quot;  StrokeThickness=&quot;1&quot; /&gt;
&lt;Border Width=&quot;20&quot; Height=&quot;20&quot;   Grid.Column=&quot;1&quot;&gt;
&lt;TextBlock Foreground=&quot;LightGray&quot; Text=&quot;+&quot; FontWeight=&quot;Bold&quot;  VerticalAlignment=&quot;Center&quot; HorizontalAlignment=&quot;Center&quot; /&gt;
&lt;/Border&gt;
&lt;/Grid&gt;
&lt;/ControlTemplate&gt;
&lt;/Setter.Value&gt;
&lt;/Setter&gt;
&lt;/Style&gt;
&lt;/Button.Style&gt;
&lt;/Button&gt;
&lt;!--&lt;Ellipse Width=&quot;20&quot; Height=&quot;20&quot; Stroke=&quot;LightGray&quot;  StrokeThickness=&quot;1&quot;  Margin=&quot;20,0,0,0&quot;/&gt;
&lt;Border Width=&quot;20&quot; Height=&quot;20&quot; Margin=&quot;20,0,0,0&quot;&gt;
&lt;TextBlock Foreground=&quot;LightGray&quot; Text=&quot;-&quot; HorizontalAlignment=&quot;Center&quot; /&gt;
&lt;/Border&gt;
&lt;Ellipse Width=&quot;20&quot; Height=&quot;20&quot; Stroke=&quot;LightGray&quot;  StrokeThickness=&quot;1&quot;  Margin=&quot;60,0,0,0&quot;/&gt;
&lt;Border Width=&quot;20&quot; Height=&quot;20&quot; Margin=&quot;60,0,0,0&quot;&gt;
&lt;TextBlock Foreground=&quot;LightGray&quot; Text=&quot;+&quot; HorizontalAlignment=&quot;Center&quot; /&gt;
&lt;/Border&gt;--&gt;
&lt;/Canvas&gt;
&lt;/Canvas&gt;
&lt;/ControlTemplate&gt;
&lt;/Setter.Value&gt;
&lt;/Setter&gt;
&lt;/Style&gt;

如何创建自定义进度条,最小值为0,从左下角开始?

答案1

得分: 0

更改Convert函数中的piang计算,以便在计算中考虑底部左侧的起始点:

double piang = (angle + 36.8) * Math.PI / 180;

这样类会如下所示:

public class AngleToPointConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double angle = (double)value;
        double radius = 50;
        double piang = (angle + 36.8) * Math.PI / 180;

        double px = Math.Sin(piang) * radius + radius;
        double py = -Math.Cos(piang) * radius + radius;

        return new System.Windows.Point(px, py);
    }

    public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
    {
        throw new NotImplementedException();
    }
}

您可能需要调整角度(36.8)。

英文:

change the piang calculation in the convert function so that the starting point at the bottom left is taken into account in the calculation

double piang = (angle - 143.2) * Math.PI / 180;

so the class looks like this

public class AngleToPointConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
{
double angle = (double)value;
double radius = 50;
double piang = (angle - 143.2) * Math.PI / 180;
//double piang = angle * Math.PI / 310;
double px = Math.Sin(piang) * radius + radius;
double py = -Math.Cos(piang) * radius + radius;
return new System.Windows.Point(px, py);
}
public object ConvertBack(object value, Type targetTypes, object parameter, System.Globalization.CultureInfo culture)
{
throw new NotImplementedException();
}
}

you may have to adjust the angle (143.2).

huangapple
  • 本文由 发表于 2023年6月1日 18:59:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/76381200.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定