C# 椭圆形进度条中的垂直指示器

C# 椭圆形进度条中的垂直指示器,c#,wpf,C#,Wpf,我正在创建一个仪表,其中我需要一个椭圆形状的进度条。我希望进度条指示器从椭圆的底部移动到顶部。我可以让它从左到右毫无问题地工作 以下是样式代码: <Style TargetType="ProgressBar" x:Key="HalfCircle"> <Setter Property="Template"> <Setter.Value> <ControlTemplate TargetType="Progre

我正在创建一个仪表,其中我需要一个椭圆形状的进度条。我希望进度条指示器从椭圆的底部移动到顶部。我可以让它从左到右毫无问题地工作

以下是样式代码:

<Style TargetType="ProgressBar" x:Key="HalfCircle">
    <Setter Property="Template">
        <Setter.Value>
            <ControlTemplate TargetType="ProgressBar">
                <Grid x:Name="gridRoot">
                    <Ellipse x:Name="PART_Track" HorizontalAlignment="Left" Height="150" Stroke="Black" VerticalAlignment="Top"  Width="150" Clip="M0.5,0.5 L153.5,0.5 L153.5,76.5 L0.5,76.5 z">
                        <Ellipse.Fill>
                            <MultiBinding>
                                <MultiBinding.Converter>
                                    <converter:ProgressBarIndicatorConverter/>
                                </MultiBinding.Converter>
                                <Binding Path="Foreground" RelativeSource="{RelativeSource TemplatedParent}"/>
                                <!--<Binding Path="Orientation" RelativeSource="{RelativeSource TemplatedParent}"/>-->
                                <!--<Binding Path="Background" RelativeSource="{RelativeSource TemplatedParent}"/>-->
                                <!--<Binding Path="Minimum" RelativeSource="{RelativeSource TemplatedParent}"/>
                                    <Binding Path="Maximum" RelativeSource="{RelativeSource TemplatedParent}"/>-->
                                <Binding Path="IsIndeterminate" RelativeSource="{RelativeSource TemplatedParent}"/>
                                <Binding Path="ActualWidth" ElementName="PART_Indicator"/>
                                <Binding Path="ActualHeight" ElementName="PART_Indicator"/>
                                <Binding Path="ActualWidth" ElementName="PART_Track"/>
                                <!--<Binding Path="ActualHeight" ElementName="PART_Track"/>-->
                            </MultiBinding>
                        </Ellipse.Fill>
                    </Ellipse>
                    <Decorator x:Name="PART_Indicator" RenderTransformOrigin="0.5,0.5" />
                </Grid>
                <!--<ControlTemplate.Triggers>
                    <Trigger Property="Orientation" Value="Vertical">

                    </Trigger>
                </ControlTemplate.Triggers>-->
            </ControlTemplate>
        </Setter.Value>
    </Setter>
</Style>

尝试此自定义控件:

    public class FlightGauge : Control
{
    private GradientStopCollection _gradStops = new GradientStopCollection();

    public static DependencyProperty MinValueProperty = DependencyProperty.Register("MinValue", typeof(double), typeof(FlightGauge), new FrameworkPropertyMetadata(-100.0, new PropertyChangedCallback(MinValue_Changed)));
    public static DependencyProperty MaxValueProperty = DependencyProperty.Register("MaxValue", typeof(double), typeof(FlightGauge), new FrameworkPropertyMetadata(100.0, new PropertyChangedCallback(MaxValue_Changed)));
    public static DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(FlightGauge), new FrameworkPropertyMetadata(0.0, new PropertyChangedCallback(Value_Changed)));
    public static DependencyProperty FillColorProperty = DependencyProperty.Register("FillColor", typeof(Color), typeof(FlightGauge), new FrameworkPropertyMetadata(Colors.Blue, new PropertyChangedCallback(FillColor_Changed)));

    public Color FillColor
    {
        get { return (Color)GetValue(FillColorProperty); }
        set { SetValue(FillColorProperty, value); }
    }


    private static void FillColor_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
    {
        FlightGauge thisClass = (FlightGauge)o;
        thisClass.SetFillColor();
    }

    private void SetFillColor()
    {
        //Put Instance FillColor Property Changed code here
    }

    public double Value
    {
        get { return (double)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }


    private static void Value_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
    {
        FlightGauge thisClass = (FlightGauge)o;
        thisClass.SetValue();
    }

    private void SetValue()
    {
        CalcTabStops();
    }


    public double MaxValue
    {
        get { return (double)GetValue(MaxValueProperty); }
        set { SetValue(MaxValueProperty, value); }
    }


    private static void MaxValue_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
    {
        FlightGauge thisClass = (FlightGauge)o;
        thisClass.SetMaxValue();
    }

    private void SetMaxValue()
    {
        CalcTabStops();
    }

    public double MinValue
    {
        get { return (double)GetValue(MinValueProperty); }
        set { SetValue(MinValueProperty, value); }
    }

    private static void MinValue_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
    {
        FlightGauge thisClass = (FlightGauge)o;
        thisClass.SetMinValue();
    }

    private void SetMinValue()
    {
        CalcTabStops();
    }


    private void CalcTabStops()
    {
        _gradStops.Clear();
        if (Value > 0)
        {
            double dLineValue = (1 - Value / MaxValue) /2;
            if (dLineValue > 0.49) dLineValue = 0.49;
            _gradStops.Add(new GradientStop(Colors.Transparent, 0.500));
            _gradStops.Add(new GradientStop(Colors.Transparent, 1.0));
            _gradStops.Add(new GradientStop(FillColor, 0.499));
            _gradStops.Add(new GradientStop(Colors.Transparent,  dLineValue));
            _gradStops.Add(new GradientStop(FillColor, dLineValue +0.001));
        }
        else
        {
            double dLineValue = 0.5 + (Value / MinValue / 2);
            if (dLineValue >= 1) dLineValue = 0.998;
            if (dLineValue == 0.5) dLineValue = 0.5001;
            _gradStops.Add(new GradientStop(Colors.Transparent, dLineValue +0.01));
            _gradStops.Add(new GradientStop(Colors.Transparent, 1.0));
            _gradStops.Add(new GradientStop(FillColor, dLineValue));
            _gradStops.Add(new GradientStop(Colors.Transparent, 0.5));
            _gradStops.Add(new GradientStop(FillColor, 0.501));
        }
        this.InvalidateVisual();
    }

    public FlightGauge()
    {
        BorderBrush = Brushes.Black;
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        Brush brush = null;
        if (Value != 0)
        {
            LinearGradientBrush linBrush = new LinearGradientBrush();
            linBrush.StartPoint = new Point(0.5, 0);
            linBrush.EndPoint = new Point(0.5, 1);
            linBrush.GradientStops = _gradStops;
            brush = linBrush;
        }
        else
        {
            brush = Brushes.Transparent;
        }
        double dX = this.ActualWidth / 2;
        double dY = this.ActualHeight / 2;
        Pen pen = new Pen(BorderBrush, 2);
        drawingContext.DrawEllipse(brush, pen, new Point(dX, dY), dX, dY);
        drawingContext.DrawLine(pen, new Point(0, dY), new Point(this.ActualWidth, dY));
        base.OnRender(drawingContext);
    }
}
示例用法:

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <local:FlightGauge x:Name="fgGauge" Width="200" Height="200" Value="{Binding ElementName=sldValue, Path=Value}" />
    <Slider Name="sldValue" Minimum="-100" Maximum="100" Value="0" Grid.Row="1" />
</Grid>


一个选项。。。你可以应用一个布局变换,然后将整个东西旋转90度?等等,这个巨大的多重绑定到底在做什么?不能使用旋转…整个半圆旋转,我希望平边是底部。多重绑定没有那么巨大…我试图添加其他属性来实现这一点。它们被注释掉了!:)啊,没注意到他们都被评论掉了。不过,如果能看到这些代码也会很好(然后我可以测试它)。我确实认为,你最好自己做一个新的控制,而不是尝试调整进度条。是的,我就是这么做的!当我看到你的解决方案时,我正要发布更新。谢谢你,凯莉。我还将发布与您类似的解决方案。
 public partial class PitchProgressBar : UserControl
{
    public static DependencyProperty ProgressIndicatorColorProperty = DependencyProperty.Register("ProgressIndicatorColor", typeof(Brush), typeof(PitchProgressBar), new PropertyMetadata(new PropertyChangedCallback(ProgressIndicatorColorPropertyChanged)));
    public static DependencyProperty ProgressIndicatorValueProperty = DependencyProperty.Register("ProgressIndicatorValue", typeof(double), typeof(PitchProgressBar), new PropertyMetadata(new PropertyChangedCallback(ProgressIndicatorValuePropertyChanged)));

    private static void ProgressIndicatorColorPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ctl = d as PitchProgressBar;
        if (ctl != null)
        {
            ctl.pbEllipse.Foreground = (Brush)e.NewValue;
        }
    }

    private static void ProgressIndicatorValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
    {
        var ctl = d as PitchProgressBar;
        if (ctl != null)
        {
            ctl.pbEllipse.Value = (double)e.NewValue;
        }
    }

    public PitchProgressBar()
    {
        InitializeComponent();

    }

  public Brush ProgressColor
    {
        get { return (Brush)GetValue(ProgressIndicatorColorProperty); }
        set { SetValue(ProgressIndicatorColorProperty, value); }
    }

    public double ProgressIndicatorValue
    {
        get { return (double)GetValue(ProgressIndicatorValueProperty); }
        set { SetValue(ProgressIndicatorValueProperty, value); }
    }
}
    public class FlightGauge : Control
{
    private GradientStopCollection _gradStops = new GradientStopCollection();

    public static DependencyProperty MinValueProperty = DependencyProperty.Register("MinValue", typeof(double), typeof(FlightGauge), new FrameworkPropertyMetadata(-100.0, new PropertyChangedCallback(MinValue_Changed)));
    public static DependencyProperty MaxValueProperty = DependencyProperty.Register("MaxValue", typeof(double), typeof(FlightGauge), new FrameworkPropertyMetadata(100.0, new PropertyChangedCallback(MaxValue_Changed)));
    public static DependencyProperty ValueProperty = DependencyProperty.Register("Value", typeof(double), typeof(FlightGauge), new FrameworkPropertyMetadata(0.0, new PropertyChangedCallback(Value_Changed)));
    public static DependencyProperty FillColorProperty = DependencyProperty.Register("FillColor", typeof(Color), typeof(FlightGauge), new FrameworkPropertyMetadata(Colors.Blue, new PropertyChangedCallback(FillColor_Changed)));

    public Color FillColor
    {
        get { return (Color)GetValue(FillColorProperty); }
        set { SetValue(FillColorProperty, value); }
    }


    private static void FillColor_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
    {
        FlightGauge thisClass = (FlightGauge)o;
        thisClass.SetFillColor();
    }

    private void SetFillColor()
    {
        //Put Instance FillColor Property Changed code here
    }

    public double Value
    {
        get { return (double)GetValue(ValueProperty); }
        set { SetValue(ValueProperty, value); }
    }


    private static void Value_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
    {
        FlightGauge thisClass = (FlightGauge)o;
        thisClass.SetValue();
    }

    private void SetValue()
    {
        CalcTabStops();
    }


    public double MaxValue
    {
        get { return (double)GetValue(MaxValueProperty); }
        set { SetValue(MaxValueProperty, value); }
    }


    private static void MaxValue_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
    {
        FlightGauge thisClass = (FlightGauge)o;
        thisClass.SetMaxValue();
    }

    private void SetMaxValue()
    {
        CalcTabStops();
    }

    public double MinValue
    {
        get { return (double)GetValue(MinValueProperty); }
        set { SetValue(MinValueProperty, value); }
    }

    private static void MinValue_Changed(DependencyObject o, DependencyPropertyChangedEventArgs args)
    {
        FlightGauge thisClass = (FlightGauge)o;
        thisClass.SetMinValue();
    }

    private void SetMinValue()
    {
        CalcTabStops();
    }


    private void CalcTabStops()
    {
        _gradStops.Clear();
        if (Value > 0)
        {
            double dLineValue = (1 - Value / MaxValue) /2;
            if (dLineValue > 0.49) dLineValue = 0.49;
            _gradStops.Add(new GradientStop(Colors.Transparent, 0.500));
            _gradStops.Add(new GradientStop(Colors.Transparent, 1.0));
            _gradStops.Add(new GradientStop(FillColor, 0.499));
            _gradStops.Add(new GradientStop(Colors.Transparent,  dLineValue));
            _gradStops.Add(new GradientStop(FillColor, dLineValue +0.001));
        }
        else
        {
            double dLineValue = 0.5 + (Value / MinValue / 2);
            if (dLineValue >= 1) dLineValue = 0.998;
            if (dLineValue == 0.5) dLineValue = 0.5001;
            _gradStops.Add(new GradientStop(Colors.Transparent, dLineValue +0.01));
            _gradStops.Add(new GradientStop(Colors.Transparent, 1.0));
            _gradStops.Add(new GradientStop(FillColor, dLineValue));
            _gradStops.Add(new GradientStop(Colors.Transparent, 0.5));
            _gradStops.Add(new GradientStop(FillColor, 0.501));
        }
        this.InvalidateVisual();
    }

    public FlightGauge()
    {
        BorderBrush = Brushes.Black;
    }

    protected override void OnRender(DrawingContext drawingContext)
    {
        Brush brush = null;
        if (Value != 0)
        {
            LinearGradientBrush linBrush = new LinearGradientBrush();
            linBrush.StartPoint = new Point(0.5, 0);
            linBrush.EndPoint = new Point(0.5, 1);
            linBrush.GradientStops = _gradStops;
            brush = linBrush;
        }
        else
        {
            brush = Brushes.Transparent;
        }
        double dX = this.ActualWidth / 2;
        double dY = this.ActualHeight / 2;
        Pen pen = new Pen(BorderBrush, 2);
        drawingContext.DrawEllipse(brush, pen, new Point(dX, dY), dX, dY);
        drawingContext.DrawLine(pen, new Point(0, dY), new Point(this.ActualWidth, dY));
        base.OnRender(drawingContext);
    }
}
<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    xmlns:local="clr-namespace:WpfApplication1"
    mc:Ignorable="d"
    Title="MainWindow" Height="350" Width="525">
<Grid>
    <Grid.RowDefinitions>
        <RowDefinition Height="*" />
        <RowDefinition Height="Auto" />
    </Grid.RowDefinitions>
    <local:FlightGauge x:Name="fgGauge" Width="200" Height="200" Value="{Binding ElementName=sldValue, Path=Value}" />
    <Slider Name="sldValue" Minimum="-100" Maximum="100" Value="0" Grid.Row="1" />
</Grid>