Ребят, подскажите как сделать полукруглый прогресс бар? С обычным вообще не возникает проблем. Находил только больно уж сложные, круглые примеры
Просто тут и не будет, придется помудрить с геометрией.
Ну что ж, давайте создадим UserControl
, я назвал его MyProgress
.
Рисовать будем с помощью Path
. Контрол будет состоять из двух Path
- закрашенного и незакрашенного (закрашенного другим цветом). Для упрощения расчетов я взял эллипс с радиусами 100 и центром в точке (100,100).
Нам нужно нарисовать 2 луча из центра и дугу:
<Path Fill="Blue" Stroke="Black">
<Path.Data>
<PathGeometry>
<PathFigure StartPoint="100,100">
<LineSegment Point="0,100"/>
<ArcSegment Point="170.71,29.29"
Size="100,100"
SweepDirection="Clockwise"/>
<LineSegment Point="100,100"/>
</PathFigure>
</PathGeometry>
</Path.Data>
</Path>
Точку я рассчитал для варианта 75% заполненности, вот что уже получается:
Теперь из этого сектора нужно вырезать круг меньшего диаметра, сделаем это с помощью CombinedGeometry
в режиме Exclude
:
<Path Fill="Blue" Stroke="Black">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<PathGeometry>
<PathFigure StartPoint="100,100">
<LineSegment Point="0,100"/>
<ArcSegment Point="170.71,29.29"
Size="100,100"
SweepDirection="Clockwise"/>
<LineSegment Point="100,100"/>
</PathFigure>
</PathGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="100,100" RadiusX="80" RadiusY="80"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
Теперь аналогично рисуем вторую часть другим цветом:
<Path Fill="Cyan" Stroke="Black">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<PathGeometry>
<PathFigure StartPoint="100,100">
<LineSegment Point="200,100"/>
<ArcSegment Point="170.71,29.29"
Size="100,100"
SweepDirection="Counterclockwise"/>
<LineSegment Point="100,100"/>
</PathFigure>
</PathGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="100,100" RadiusX="80" RadiusY="80"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
С разметкой пока всё, останется только привязать координаты рассчитанной точки в ArcSegment
.
Займемся кодом контрола:
Свойство зависимости Value
:
public static DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double),
typeof(MyProgress), new FrameworkPropertyMetadata(OnValueChanged));
Вспомогательное свойство зависимости с координатами точки дуги:
protected static DependencyProperty AuxiliaryPointProperty = DependencyProperty.Register("AuxiliaryPoint",
typeof(Point), typeof(MyProgress));
Стандартные оболочки для этих свойств:
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
protected Point AuxiliaryPoint
{
get => (Point)GetValue(AuxiliaryPointProperty);
set => SetValue(AuxiliaryPointProperty, value);
}
Ну и, наконец, метод, который будет пересчитывать координаты точки при смене Value
:
static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var myProgress = (MyProgress)d;
var value = (double)e.NewValue;
var angle = Math.PI * value / 100;
var x = 100 - 100 * Math.Cos(angle);
var y = 100 - 100 * Math.Sin(angle);
myProgress.AuxiliaryPoint = new Point(x, y);
}
Теперь в разметке привяжемся к рассчитанной точке:
Point="{Binding ElementName=myProgress, Path=AuxiliaryPoint}"
Это нужно сделать для обоих ArcSegment
В разметке я дал имя контролу для упрощения кода привязки:
<UserControl ...
Name="myProgress">
Всё. Это уже минимально рабочий прогрессбар, который можно добавить в окно:
<local:MyProgress x:Name="Progress1" Value="0"/>
Выглядит так:
Имейте ввиду, чтобы сделать этот контрол более-менее универсальным, вам потребуется его еще доработать, например, вынести в свойства зависимости цвета дуг и фона, минимальное и максимальное значение прогрессбара, диаметр внешнего и внутреннего круга и т.д.
Привожу код контрола полностью, MyProgress.xaml
:
<UserControl x:Class="WpfProgress.MyProgress"
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" Name="myProgress">
<Grid>
<Path Fill="Blue" Stroke="Black">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<PathGeometry>
<PathFigure StartPoint="100,100">
<LineSegment Point="0,100"/>
<ArcSegment Point="{Binding ElementName=myProgress, Path=AuxiliaryPoint}"
Size="100,100" SweepDirection="Clockwise"/>
<LineSegment Point="100,100"/>
</PathFigure>
</PathGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="100,100" RadiusX="80" RadiusY="80"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
<Path Fill="Cyan" Stroke="Black">
<Path.Data>
<CombinedGeometry GeometryCombineMode="Exclude">
<CombinedGeometry.Geometry1>
<PathGeometry>
<PathFigure StartPoint="100,100">
<LineSegment Point="200,100"/>
<ArcSegment Point="{Binding ElementName=myProgress, Path=AuxiliaryPoint}"
Size="100,100" SweepDirection="Counterclockwise"/>
<LineSegment Point="100,100"/>
</PathFigure>
</PathGeometry>
</CombinedGeometry.Geometry1>
<CombinedGeometry.Geometry2>
<EllipseGeometry Center="100,100" RadiusX="80" RadiusY="80"/>
</CombinedGeometry.Geometry2>
</CombinedGeometry>
</Path.Data>
</Path>
</Grid>
</UserControl>
MyProgress.xaml.cs
:
using System;
using System.Windows;
using System.Windows.Controls;
namespace WpfProgress
{
public partial class MyProgress : UserControl
{
public MyProgress()
{
InitializeComponent();
}
public static DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double),
typeof(MyProgress), new FrameworkPropertyMetadata(OnValueChanged));
protected static DependencyProperty AuxiliaryPointProperty = DependencyProperty.Register("AuxiliaryPoint",
typeof(Point), typeof(MyProgress));
static void OnValueChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var myProgress = (MyProgress)d;
var value = (double)e.NewValue;
var angle = Math.PI * value / 100;
var x = 100 - 100 * Math.Cos(angle);
var y = 100 - 100 * Math.Sin(angle);
myProgress.AuxiliaryPoint = new Point(x, y);
}
public double Value
{
get => (double)GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
protected Point AuxiliaryPoint
{
get => (Point)GetValue(AuxiliaryPointProperty);
set => SetValue(AuxiliaryPointProperty, value);
}
}
}
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Добрый день У меня возникла проблема, так как в использовании данного фреймворка я новичокЯ хотел создать самый простой и обычный task manager
Здравствуйте, скажите пожалуйста зачем и в чём удобства Converter'а в Binding'е?
У меня есть SVG, который содержит электрическую схемуИспользуя Xamarin я вывел схему на экран