循环进度条问题

时间:2015-11-02 16:26:58

标签: c# wpf

我已经调整了一些我在网上找到的循环进度条的代码,它可以工作,直到进度条达到100%,然后它就消失了......

我无法解决出错的问题,我假设它与ArcSegment的工作方式有关但我不完全理解背后的数学,有人可以告诉我?

这是ProgressBar和Slider:

<Slider Value="{Binding Source={StaticResource runtimeVariables}, Path=uploadProgress}" Maximum="100" Margin="0,0,252,0" />
        <ProgressBar Width="150" Style="{StaticResource CircularProgress}" Value="{Binding Source={StaticResource runtimeVariables},Path=uploadProgress}" Maximum="100" HorizontalAlignment="Left" />

这是样式和转换器

<CircleProgress:StartPointConverter x:Key="StartPointConverter" />
    <CircleProgress:ArcSizeConverter x:Key="ArcSizeConverter" />
    <CircleProgress:ArcEndPointConverter x:Key="ArcEndPointConverter" />
    <CircleProgress:LargeArcConverter x:Key="LargeArcConverter" />
    <CircleProgress:SizeTextOnParent x:Key="SizeTextOnParent" />
    <CircleProgress:Difference x:Key="Difference" />

    <Style TargetType="ProgressBar" x:Key="CircularProgress">
        <Setter Property="Template">
            <Setter.Value>
                <ControlTemplate TargetType="ProgressBar">
                    <Grid x:Name="PathGrid" Width="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Width}">
                        <Canvas>
                            <DockPanel Height="{Binding ElementName=PathGrid, Path=Width}" Width="{Binding ElementName=PathGrid, Path=Width}">
                                <TextBlock x:Name="PathPercentage" 
                                           Text="{Binding RelativeSource={RelativeSource TemplatedParent},Path=Value, StringFormat={}{0}%}"
                                           Foreground="White"
                                           FontSize="{Binding ElementName=PathGrid, Path=ActualWidth, Converter={StaticResource SizeTextOnParent}}" 
                                           VerticalAlignment="Center" TextAlignment="Center">
                                </TextBlock>
                            </DockPanel>
                            <Path x:Name="pathRoot"
                                  Panel.ZIndex="1"
                                  Stroke="#8ab71c" 
                                  StrokeThickness="6" 
                                  HorizontalAlignment="Center" 
                                  VerticalAlignment="Top">
                                <Path.Data>
                                    <PathGeometry>
                                        <PathFigureCollection>
                                            <PathFigure StartPoint="{Binding ElementName=PathGrid, Path=ActualWidth, Converter={StaticResource StartPointConverter}, Mode=OneWay}">
                                                <ArcSegment Size="{Binding ElementName=PathGrid, Path=ActualWidth, Converter={StaticResource ArcSizeConverter}, Mode=OneWay}" SweepDirection="Clockwise">
                                                    <ArcSegment.IsLargeArc>
                                                        <MultiBinding Converter="{StaticResource LargeArcConverter}">
                                                            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value" />
                                                            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum" />
                                                            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum" />
                                                        </MultiBinding>
                                                    </ArcSegment.IsLargeArc>
                                                    <ArcSegment.Point>
                                                        <MultiBinding Converter="{StaticResource ArcEndPointConverter}">
                                                            <Binding ElementName="PathGrid" Path="ActualWidth" />
                                                            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Value" />
                                                            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Minimum" />
                                                            <Binding RelativeSource="{RelativeSource TemplatedParent}" Path="Maximum" />
                                                        </MultiBinding>
                                                    </ArcSegment.Point>
                                                </ArcSegment>
                                            </PathFigure>
                                        </PathFigureCollection>
                                    </PathGeometry>
                                </Path.Data>
                            </Path>
                            <Ellipse
                                x:Name="backCircle"
                                Panel.ZIndex="0"
                                Fill="Transparent"
                                Stroke="#434953" 
                                StrokeThickness="3" 
                                Width="{Binding ElementName=PathGrid, Path=Width}" 
                                Height="{Binding ElementName=PathGrid, Path=Width}" />
                        </Canvas>
                    </Grid>
                </ControlTemplate>
            </Setter.Value>
        </Setter>
    </Style>

ArcEndPointConverter.cs

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace Test_Project.Converters
{
    public class ArcEndPointConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var actualWidth = values[0].ExtractDouble();
            var value = values[1].ExtractDouble();
            var minimum = values[2].ExtractDouble();
            var maximum = values[3].ExtractDouble();

            if (new[] { actualWidth, value, minimum, maximum }.AnyNan())
                return Binding.DoNothing;

            if (values.Length == 5)
            {
                var fullIndeterminateScaling = values[4].ExtractDouble();
                if (!double.IsNaN(fullIndeterminateScaling) && fullIndeterminateScaling > 0.0)
                {
                    value = (maximum - minimum) * fullIndeterminateScaling;
                }
            }

            var percent = maximum <= minimum ? 1.0 : (value - minimum) / (maximum - minimum);
            var degrees = 360 * percent;
            var radians = degrees * (Math.PI / 180);

            var centre = new Point(actualWidth / 2, actualWidth / 2);
            var hypotenuseRadius = (actualWidth / 2);

            var adjacent = Math.Cos(radians) * hypotenuseRadius;
            var opposite = Math.Sin(radians) * hypotenuseRadius;

            return new Point(centre.X + opposite, centre.Y - adjacent);
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

ArcSizeConverter.cs

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace Test_Project.Converters
{
    public class ArcSizeConverter : IValueConverter
    {
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double && ((double)value > 0.0))
            {
                return new Size((double)value / 2, (double)value / 2);
            }

            return new Point();
        }

        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Binding.DoNothing;
        }
    }
}

LargeArcConverter.cs

using System;
using System.Globalization;
using System.Windows.Data;

namespace Test_Project.Converters
{
    public class LargeArcConverter : IMultiValueConverter
    {
        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
        {
            var value = values[0].ExtractDouble();
            var minimum = values[1].ExtractDouble();
            var maximum = values[2].ExtractDouble();

            if (new[] { value, minimum, maximum }.AnyNan())
                return Binding.DoNothing;

            if (values.Length == 4)
            {
                var fullIndeterminateScaling = values[3].ExtractDouble();
                if (!double.IsNaN(fullIndeterminateScaling) && fullIndeterminateScaling > 0.0)
                {
                    value = (maximum - minimum) * fullIndeterminateScaling;
                }
            }

            var percent = maximum <= minimum ? 1.0 : (value - minimum) / (maximum - minimum);

            return percent > 0.5;
        }

        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
        {
            throw new NotImplementedException();
        }
    }
}

StartPointConverter.cs

using System;
using System.Globalization;
using System.Windows;
using System.Windows.Data;

namespace Test_Project.Converters
{
    public class StartPointConverter : IValueConverter
    {
        [Obsolete]
        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
        {
            if (value is double && ((double)value > 0.0))
            {
                return new Point((double)value / 2, 0);
            }

            return new Point();
        }

        [Obsolete]
        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
        {
            return Binding.DoNothing;
        }

    }
}

1 个答案:

答案 0 :(得分:4)

我有一个非常快速的解决方法,你不需要改变任何东西,但它仍然是一种解决方法;)

在您的ArcEndPointConverter中添加此行

if (degrees == 360) degrees = 359.99;

在转换为Radians 之前只是,我认为否则该值等于你的结束度为0°时的值,所以我们只是把它逼近360°以便它可以自我绘制(我的测试它对人眼来说是不可见的)

...
var percent = maximum <= minimum ? 1.0 : (value - minimum) / (maximum - minimum);
var degrees = 360 * percent;
if (degrees == 360) degrees = 359.99;
var radians = degrees * (Math.PI / 180);
...