Как создать ProgressBar с круговым стилем

Динамические Языки могут изменить объект во время выполнения, можно добавить методы, свойства...

Одним хорошим примером Динамического волшебства Языков является этот фрагмент кода Groovy, которые называют метод на веб-сервисе во всего двух строках кода:

def proxy = new SoapClient("http://localhost:6980/MathServiceInterface?wsdl");
def result = proxy.add(1.0, 2.0);

Это - другой отрывок Groovy, которые извлекают данные из XML:

def contacts = new XmlParser().parseText("<contacts><name>Bahaa Zaid</name></contacts>");
def myName = contacts.name[0].text();

Вы не можете сделать этого на Статических Языках. Динамический Язык может изменить объекты отразить фактическое условие во время выполнения.

23
задан Jalal 17 December 2017 в 16:49
поделиться

4 ответа

У вас есть пара опций - во-первых, это шаблон элемента управления ProgressBar. Это оказывается немного сложнее. Я написал пост в блоге, в котором описано, как использовать прилагаемую ViewModel для достижения требуемого эффекта .

Другой альтернативой является создание собственного контроля с нуля. Вы можете сделать следующее:

  1. Создать новый пользовательский элемент управления
  2. Добавить новые свойства Value, Maximum и Minimum зависимостей.
  3. Обработайте события изменения значения Value, Maximum и Minimum в вашем пользовательском элементе управления для вычисления свойства Angle.
  4. Создайте два «кусочка пирога» в коде позади (см. этот пост ) и добавьте их в пользовательский интерфейс.
22
ответ дан 29 November 2019 в 01:35
поделиться

Это немного сложно, но не невозможно. Вот моя реализация, использующая плавную анимацию для руководства. Для создания CircularProgressBar следует использовать преобразователи значений.

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

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>

Его можно настроить, добавив еще несколько свойств, таких как InnerRadius, Radius и т. Д.

13
ответ дан 29 November 2019 в 01:35
поделиться

Я знаю, что это старая проблема, но в любом случае вот мое решение:

ДЛЯ WINFORMS:

using System;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Windows.Forms;

public class CircularProgressBar : Control
{
    /*  CREDITS:
     *  Autor: Sajjad Arif Gul / October 12, 2016 / C#, Source Codes
     *  https://www.csharpens.com/c-sharp/circular-progress-bar-in-c-sharp-windows-form-applications-23/
     *  Modified by Jhollman Chacon, 2017 */

#region Enums

public enum _ProgressShape
{
    Round,
    Flat
}

#endregion

#region Variables

private long _Value;
private long _Maximum = 100;
private Color _ProgressColor1 = Color.Orange;
private Color _ProgressColor2 = Color.Orange;
private Color _LineColor = Color.Silver;
private _ProgressShape ProgressShapeVal;

#endregion

#region Custom Properties

public long Value
{
    get { return _Value; }
    set
    {
        if (value > _Maximum)
            value = _Maximum;
        _Value = value;
        Invalidate();
    }
}

public long Maximum
{
    get { return _Maximum; }
    set
    {
        if (value < 1)
            value = 1;
        _Maximum = value;
        Invalidate();
    }
}

public Color ProgressColor1
{
    get { return _ProgressColor1; }
    set
    {
        _ProgressColor1 = value;
        Invalidate();
    }
}

public Color ProgressColor2
{
    get { return _ProgressColor2; }
    set
    {
        _ProgressColor2 = value;
        Invalidate();
    }
}

public Color LineColor
{
    get { return _LineColor; }
    set
    {
        _LineColor = value;
        Invalidate();
    }
}

public _ProgressShape ProgressShape
{
    get { return ProgressShapeVal; }
    set
    {
        ProgressShapeVal = value;
        Invalidate();
    }
}

#endregion

#region EventArgs

protected override void OnResize(EventArgs e)
{
    base.OnResize(e);
    SetStandardSize();
}

protected override void OnSizeChanged(EventArgs e)
{
    base.OnSizeChanged(e);
    SetStandardSize();
}

protected override void OnPaintBackground(PaintEventArgs p)
{
    base.OnPaintBackground(p);
}

#endregion

#region Methods
public CircularProgressBar()
{
    Size = new Size(130, 130);
    Font = new Font("Segoe UI", 15);
    MinimumSize = new Size(100, 100);
    DoubleBuffered = true;
    Value = 57;
    ProgressShape = _ProgressShape.Flat;
    this.ForeColor = Color.DimGray;
}

private void SetStandardSize()
{
    int _Size = Math.Max(Width, Height);
    Size = new Size(_Size, _Size);
}

public void Increment(int Val)
{
    this._Value += Val;
    Invalidate();
}

public void Decrement(int Val)
{
    this._Value -= Val;
    Invalidate();
}
#endregion

#region Events
protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    using (Bitmap bitmap = new Bitmap(this.Width, this.Height))
    {
        using (Graphics graphics = Graphics.FromImage(bitmap))
        {
            graphics.SmoothingMode = SmoothingMode.AntiAlias;
            graphics.Clear(this.BackColor);

            // Dibuja la Linea
            using (Pen pen2 = new Pen(LineColor))
            {
                graphics.DrawEllipse(pen2, 0x18 - 6, 0x18 - 6, (this.Width - 0x30) + 12, (this.Height - 0x30) + 12);
            }

            //Dibuja la Barra de Progreso
            using (LinearGradientBrush brush = new LinearGradientBrush(this.ClientRectangle, this._ProgressColor1, this._ProgressColor2, LinearGradientMode.ForwardDiagonal))
            {
                using (Pen pen = new Pen(brush, 14f))
                {
                    switch (this.ProgressShapeVal)
                    {
                        case _ProgressShape.Round:
                            pen.StartCap = LineCap.Round;
                            pen.EndCap = LineCap.Round;
                            break;

                        case _ProgressShape.Flat:
                            pen.StartCap = LineCap.Flat;
                            pen.EndCap = LineCap.Flat;
                            break;
                    }
                    //Aqui se dibuja el Progreso
                    graphics.DrawArc(pen, 0x12, 0x12, (this.Width - 0x23) - 2, (this.Height - 0x23) - 2, -90, (int)Math.Round((double)((360.0 / ((double)this._Maximum)) * this._Value)));
                }
            }

            //Dibuja el Texto de Progreso:
            Brush FontColor = new SolidBrush(this.ForeColor);
            SizeF MS = graphics.MeasureString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font);
            graphics.DrawString(Convert.ToString(Convert.ToInt32((100 / _Maximum) * _Value)), Font, FontColor, Convert.ToInt32(Width / 2 - MS.Width / 2), Convert.ToInt32(Height / 2 - MS.Height / 2));
            e.Graphics.DrawImage(bitmap, 0, 0);
            graphics.Dispose();
            bitmap.Dispose();
        }
    }
} 
#endregion
}

РЕАЛИЗАЦИЯ:

  1. Разместите источник код в новый класс в любом месте вашего проекта WinForms, назовите класс ' CircularProgressBar.cs '.
  2. Скомпилируйте проект.
  3. После компиляции вы должны увидеть новый элемент управления или «Компонент» на панели инструментов.
  4. Перетащите этот новый элемент управления в любую форму и настройте его свойства.

Управление выглядит следующим образом:

Control Preview

Наслаждайтесь.

9
ответ дан 29 November 2019 в 01:35
поделиться

Вы смотрели на ValueConverter с? Вы можете привязать свойство Value в шаблоне, используя TemplateBinding, и использовать соответствующий конвертер значений, чтобы изменить значение на то, что полезно для круглого индикатора выполнения.

РЕДАКТИРОВАТЬ:

В шаблоне:

  1. Добавить кружок, заполненный желтым.

  2. Добавьте еще один круг сверху с оранжевым цветом.

  3. Используйте преобразователь значений (или преобразователь нескольких значений), чтобы вернуть геометрию отсечения (возможно, с использованием дугового сегмента) для круга, добавленного в 2.

  4. Обрезать круг в 2. с геометрией, возвращенной в 3.

  5. Downvoter возвращает мне мой реп.

6
ответ дан 29 November 2019 в 01:35
поделиться
Другие вопросы по тегам:

Похожие вопросы: