public static DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double),
typeof(MyProgress), new FrameworkPropertyMetadata(OnValueChanged));
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);
}
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);
}
}
}
对于那些想要创建这样一个控件的人 - 添加到项目Add - New Item - Custom Control WPF中,我给它命名SemicircleProgressBar,控件本身的代码非常简单 - 添加了一个依赖属性:
public class SemicircleProgressBar : ProgressBar
{
static SemicircleProgressBar()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(SemicircleProgressBar),
new FrameworkPropertyMetadata(typeof(SemicircleProgressBar)));
}
public static DependencyProperty CuttingFactorProperty =
DependencyProperty.Register(nameof(CuttingFactor), typeof(double),
typeof(SemicircleProgressBar), new FrameworkPropertyMetadata(0.8));
public double CuttingFactor
{
get => (double)GetValue(CuttingFactorProperty);
set => SetValue(CuttingFactorProperty, value);
}
}
class ValueToAuxiliaryPointConverter : IMultiValueConverter
{
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
{
if (values.Contains(DependencyProperty.UnsetValue))
return DependencyProperty.UnsetValue;
var v = (double)values[0];
var min = (double)values[1];
var max = (double)values[2];
var r = (double)values[3];
var ratio = (v - min) / (max - min);
var angle = Math.PI * ratio;
var x = 1 - r * Math.Cos(angle);
var y = 1 - r * Math.Sin(angle);
return new Point(x, y);
}
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
RadiusToSizeConverter:
class RadiusToSizeConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
var r = (double)value;
return new Size(r, r);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
它只是不会在这里,你必须对几何学很聪明。
好吧,让我们创建
UserControl,我称之为MyProgress。我们将画画
Path。该控件将由两个组成Path- 已填充和未绘制(以不同颜色绘制)。为了简化计算,我取了一个半径为 100 且中心位于点 (100,100) 的椭圆。我们需要从中心绘制 2 条射线和一条弧线:
我计算了 75% 占用选项的分数,这是我已经得到的:
现在你需要从这个扇区切出一个直径较小的圆,我们将使用
CombinedGeometry以下模式来完成Exclude:现在同样用不同的颜色绘制第二部分:
有了标记,现在就这些了,剩下的就是将计算点的坐标绑定到
ArcSegment.我们看一下控制代码:
依赖属性
Value:具有圆弧点坐标的辅助依赖属性:
这些属性的标准包装器:
最后,一种在更改时重新计算点坐标的方法
Value:现在,在标记中,我们将绑定到计算点:
两者都需要这样做。
ArcSegment在标记中,我为控件命名以简化绑定代码:
一切。这已经是可以添加到窗口的最小工作进度条了:
看起来像这样:
请记住,为了使此控件或多或少具有通用性,您需要进一步细化它,例如,移动圆弧和背景颜色的依赖关系、进度条的最小值和最大值、进度条的直径外圈和内圈等进入属性。
这是完整的控制代码
MyProgress.xaml:MyProgress.xaml.cs:由于
UserControl它是非语义的,我为ProgressBar. 然后我决定添加从标记编辑内半径的功能。但是改变控件行为的附加属性也是非语义的,所以最后我选择了Custom Control,继承自ProgressBar。思路和上面解决方案中描述的是一样的,但是现在控件已经完全敲定了(大概),所以标记因为一堆绑定变得更加复杂,也因为实现的模式
Indeterminate。对于那些想要创建这样一个控件的人 - 添加到项目
Add - New Item - Custom Control WPF中,我给它命名SemicircleProgressBar,控件本身的代码非常简单 - 添加了一个依赖属性:在项目根目录下出现
Generic.xaml的文件Themes中,标记出新控件的样式:转换器。
ValueToAuxiliaryPointConverter:RadiusToSizeConverter:演示代码:
使用此答案中的信息