0

I have got a wpf c# code that generates a circular progress bar, but I need to change it's size, suppose need to reduce size by factor of 2 or whatever. The only thing ii need to know is how to resize the circle, I have made some attempts, but all resulted in a deformed control. The source of my code is available here by Ali Tor In the following is my code: enter image description here

CircularProgressBar.cs

 public partial class CircularProgressBar : ProgressBar
{
    public CircularProgressBar()
    {
        this.ValueChanged += CircularProgressBar_ValueChanged;
    }

    void CircularProgressBar_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
    {
        CircularProgressBar bar = sender as CircularProgressBar;
        double currentAngle = bar.Angle;
        double targetAngle = e.NewValue / bar.Maximum * 359.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("Angle", 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("StrokeThickness", typeof(double), typeof(CircularProgressBar), new PropertyMetadata(10.0));
}

AngleToPointConverter.cs:

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 px = Math.Sin(piang) * radius + radius;
        double py = -Math.Cos(piang) * radius + radius;

        return new Point(px, py);
    }

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

AngleToIsLargeConverter.cs

public class AngleToIsLargeConverter : IValueConverter
{

    public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
    {
        double angle = (double)value;

        return angle > 180;
    }

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

App.xaml:

<Application x:Class="WpfApplication1.App"
         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
         StartupUri="MainWindow.xaml"
         xmlns:my="clr-namespace:WpfApplication1">
<Application.Resources>
    <my:AngleToPointConverter x:Key="prConverter"/>
    <my:AngleToIsLargeConverter x:Key="isLargeConverter"/>

    <Style x:Key="circularProgressBar" TargetType="my:CircularProgressBar">
        <Setter Property="Value" Value="10"/>
        <Setter Property="Maximum" Value="100"/>
        <Setter Property="StrokeThickness" Value="10"/>
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="my:CircularProgressBar">
                        <Canvas Width="100" Height="100">
                        <Ellipse Width="100" Height="100" Stroke="LightGray"
                                     StrokeThickness="1"/>

                        <Path Stroke="{TemplateBinding Background}" 
                                  StrokeThickness="{TemplateBinding StrokeThickness}">
                                <Path.Data>
                                    <PathGeometry>
                                        <PathFigure x:Name="fig" StartPoint="50,0">
                                            <ArcSegment RotationAngle="0" SweepDirection="Clockwise"
                                                        Size="50,50"
                                                        Point="{Binding Path=Angle, Converter={StaticResource prConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}"
                                                        IsLargeArc="{Binding Path=Angle, Converter={StaticResource isLargeConverter}, RelativeSource={RelativeSource FindAncestor, AncestorType=ProgressBar}}"
                                                        >
                                            </ArcSegment>
                                        </PathFigure>
                                    </PathGeometry>
                                </Path.Data>
                            </Path>
                            <Border Width="100" Height="100">
                                <TextBlock Foreground="Gray" HorizontalAlignment="Center" VerticalAlignment="Center"
                                       Text="{Binding Path=Value, StringFormat={}%{0}, 
                                RelativeSource={RelativeSource TemplatedParent}}"
                                           FontSize="{TemplateBinding FontSize}"/>
                            </Border>
                        </Canvas>

                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>
</Application.Resources>
Galilo Galilo
  • 519
  • 5
  • 22
  • Just from having a quick glance at your code I would change following lines (to double the size): AngleToPointConverter.cs: double radius = 100; App.xaml: and I recommend to pass the radius as ConverterParameter to the converter to eliminate the need for modification each time the radius changes. Setting or adjusting the Canvas dimensions is not necessary. – BionicCode Mar 20 '19 at 07:23
  • thanks for your attempt, but when applying the mentioned changes, it seems that the arc starting point doesn't fit with the new sizes. – Galilo Galilo Mar 20 '19 at 07:55
  • __ and __. Then add a name to the Ellipse: __ Since the ellipse is a circle I added a binding from hight to width. – BionicCode Mar 20 '19 at 08:27
  • I'm not good with styling, but maybe [this](https://github.com/MaterialDesignInXAML/MaterialDesignInXamlToolkit/blob/master/MaterialDesignThemes.Wpf/Themes/MaterialDesignTheme.ProgressBar.xaml) will help you. This is a style that fully changes progress bar to cricular using just the style, no inheritance – Krzysztof Skowronek Mar 20 '19 at 09:03
  • 1
    Have you tried to put your `Canvas` into a `ViewBox` and set the `Width` or `Height` Property of the `CircularProgressBar` to a scaled Value? (eg. `` for double Size and `` for half the Size) – LittleBit Mar 20 '19 at 11:09
  • Thank u all for attempts to help. You have solved my problem @LittleBit. – Galilo Galilo Mar 21 '19 at 04:57
  • If anyone will ever want to play with radial progress bars, feel free to check: https://github.com/panthernet/XamlRadialProgressBar – Alexander Smirnov Mar 07 '20 at 20:33

0 Answers0