Skip to content
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,7 @@
<Content Include="SamplePages\ParallaxService\Parallax.png" />
<Content Include="SamplePages\PrintHelper\PrintHelper.png" />
<Content Include="SamplePages\PullToRefreshListView\PullToRefreshListView.png" />
<Content Include="SamplePages\RadialProgressBar\RadialProgressBar.png" />
<Content Include="SamplePages\ScrollHeader\ScrollHeader.png" />
<Content Include="SamplePages\RadialGauge\RadialGauge.png" />
<Content Include="SamplePages\RangeSelector\RangeSelector.png" />
Expand Down Expand Up @@ -371,6 +372,7 @@
<Content Include="SamplePages\MarkdownTextBlock\InitialContent.md" />
<Content Include="SamplePages\AdvancedCollectionView\AdvancedCollectionView.bind" />
<Content Include="SamplePages\TextBoxRegex\TextBoxRegex.bind" />
<Content Include="SamplePages\RadialProgressBar\RadialProgressBarCode.bind" />
<Content Include="SamplePages\MarkdownTextBlock\MarkdownTextBlockCode.bind" />
<Content Include="SamplePages\OneDrive Service\OneDriveCode.bind" />
<Content Include="SamplePages\Analytics\AnalyticsCode.bind" />
Expand Down Expand Up @@ -474,6 +476,9 @@
<Compile Include="SamplePages\TileControl\TileControlPage.xaml.cs">
<DependentUpon>TileControlPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\RadialProgressBar\RadialProgressBarPage.xaml.cs">
<DependentUpon>RadialProgressBarPage.xaml</DependentUpon>
</Compile>
<Compile Include="SamplePages\ScrollHeader\ScrollHeaderPage.xaml.cs">
<DependentUpon>ScrollHeaderPage.xaml</DependentUpon>
</Compile>
Expand Down Expand Up @@ -706,6 +711,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\RadialProgressBar\RadialProgressBarPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="SamplePages\ScrollHeader\ScrollHeaderPage.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<Page x:Class="Microsoft.Toolkit.Uwp.SampleApp.SamplePages.RadialProgressBarPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid VerticalAlignment="Center"
HorizontalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50"></ColumnDefinition>
<ColumnDefinition Width="250"></ColumnDefinition>
<ColumnDefinition Width="50"></ColumnDefinition>
</Grid.ColumnDefinitions>
<controls:RadialProgressBar
x:Name="RadialProgressBar"
Grid.Column="1"
Value="@[Value:Slider:0:0-100]"
Thickness="@[Thickness:Slider:4:4-20]"
Minimum="0"
Maximum="100"
Width="@[Width:Slider:100:100-200]"
Height="@[Height:Slider:100:100-200]"/>
</Grid>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to also add the Color enum for the Outline(Background) and Foreground so the show up as properties?

</Grid>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<Page x:Class="Microsoft.Toolkit.Uwp.SampleApp.SamplePages.RadialProgressBarPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:controls="using:Microsoft.Toolkit.Uwp.UI.Controls"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">

<Grid Background="{StaticResource Brush-Grey-05}">
<Grid HorizontalAlignment="Center"
VerticalAlignment="Center">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="50" />
<ColumnDefinition Width="250" />
<ColumnDefinition Width="50" />
</Grid.ColumnDefinitions>
<controls:RadialProgressBar x:Name="RadialProgressBarControl"
Grid.Column="1"
Maximum="100"
Minimum="0"
Thickness="{Binding Thickness.Value, Mode=OneWay}"
Value="{Binding Value.Value, Mode=OneWay}"
Width="{Binding Width.Value, Mode=OneWay}"
Height="{Binding Height.Value, Mode=OneWay}"/>
</Grid>
</Grid>
</Page>
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************

using Microsoft.Toolkit.Uwp.SampleApp.Models;

using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Navigation;

namespace Microsoft.Toolkit.Uwp.SampleApp.SamplePages
{
public sealed partial class RadialProgressBarPage : Page
{
public RadialProgressBarPage()
{
InitializeComponent();
}

protected override void OnNavigatedTo(NavigationEventArgs e)
{
base.OnNavigatedTo(e);

var propertyDesc = e.Parameter as PropertyDescriptor;

if (propertyDesc != null)
{
DataContext = propertyDesc.Expando;
}
}
}
}
8 changes: 8 additions & 0 deletions Microsoft.Toolkit.Uwp.SampleApp/SamplePages/samples.json
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,14 @@
"Icon": "/SamplePages/RadialGauge/RadialGauge.png",
"DocumentationUrl": "https://raw.githubusercontent.com/Microsoft/UWPCommunityToolkit/dev/docs/controls/RadialGauge.md"
},
{
"Name": "RadialProgressBar",
"Type": "RadialProgressBarPage",
"About": "The radial progress bar displays progress as a circle getting filled.",
"CodeUrl": "https://github.com/Microsoft/UWPCommunityToolkit/tree/master/Microsoft.Toolkit.Uwp.UI.Controls/RadialProgressBar",
"XamlCodeFile": "RadialProgressBarCode.bind",
"Icon": "/SamplePages/RadialProgressBar/RadialProgressBar.png"
},
{
"Name": "SlidableListItem",
"Type": "SlidableListItemPage",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
<Compile Include="BladeView\BladeItem.Events.cs" />
<Compile Include="MasterDetailsView\MasterDetailsViewState.cs" />
<Compile Include="ScrollHeader\ScrollHeaderMode.cs" />
<Compile Include="RadialProgressBar\RadialProgressBar.cs" />
<Compile Include="SlidableListItem\SwipeStatus.cs" />
<Compile Include="SlidableListItem\SwipeStatusChangedEventArgs.cs" />
<Compile Include="SurfaceDialTextboxHelper\SurfaceDialTextboxHelper.cs" />
Expand Down Expand Up @@ -202,6 +203,10 @@
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="RadialProgressBar\RadialProgressBar.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="ScrollHeader\ScrollHeader.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
// ******************************************************************
// Copyright (c) Microsoft. All rights reserved.
// This code is licensed under the MIT License (MIT).
// THE CODE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
// IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
// TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH
// THE CODE OR THE USE OR OTHER DEALINGS IN THE CODE.
// ******************************************************************

using System;
using Windows.Foundation;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;

namespace Microsoft.Toolkit.Uwp.UI.Controls
{
/// <summary>
/// An alternative impementation of a progress bar.
/// Progression is represented by a loop filling up in a clockwise fashion.
/// Like the traditional progress bar, it inherits from RangeBase, so Minimum, Maximum and Value properties work the same way.
/// </summary>
[TemplatePart(Name = OutlineFigurePartName, Type = typeof(PathFigure))]
[TemplatePart(Name = OutlineArcPartName, Type = typeof(ArcSegment))]
[TemplatePart(Name = BarFigurePartName, Type = typeof(PathFigure))]
[TemplatePart(Name = BarArcPartName, Type = typeof(ArcSegment))]
public sealed class RadialProgressBar : ProgressBar
{
private const string OutlineFigurePartName = "OutlineFigurePart";
private const string OutlineArcPartName = "OutlineArcPart";
private const string BarFigurePartName = "BarFigurePart";
private const string BarArcPartName = "BarArcPart";

private PathFigure outlineFigure;
private PathFigure barFigure;
private ArcSegment outlineArc;
private ArcSegment barArc;

private bool allTemplatePartsDefined = false;

/// <summary>
/// Called when the Minimum property changes.
/// </summary>
/// <param name="oldMinimum">Old value of the Minimum property.</param>
/// <param name="newMinimum">New value of the Minimum property.</param>
protected override void OnMinimumChanged(double oldMinimum, double newMinimum)
{
base.OnMinimumChanged(oldMinimum, newMinimum);
RenderSegment();
}

/// <summary>
/// Called when the Maximum property changes.
/// </summary>
/// <param name="oldMaximum">Old value of the Maximum property.</param>
/// <param name="newMaximum">New value of the Maximum property.</param>
protected override void OnMaximumChanged(double oldMaximum, double newMaximum)
{
base.OnMaximumChanged(oldMaximum, newMaximum);
RenderSegment();
}

/// <summary>
/// Called when the Value property changes.
/// </summary>
/// <param name="oldValue">Old value of the Value property.</param>
/// <param name="newValue">New value of the Value property.</param>
protected override void OnValueChanged(double oldValue, double newValue)
{
base.OnValueChanged(oldValue, newValue);
RenderSegment();
}

/// <summary>
/// Update the visual state of the control when its template is changed.
/// </summary>
protected override void OnApplyTemplate()
{
base.OnApplyTemplate();

outlineFigure = GetTemplateChild(OutlineFigurePartName) as PathFigure;
outlineArc = GetTemplateChild(OutlineArcPartName) as ArcSegment;
barFigure = GetTemplateChild(BarFigurePartName) as PathFigure;
barArc = GetTemplateChild(BarArcPartName) as ArcSegment;

allTemplatePartsDefined = outlineFigure != null && outlineArc != null && barFigure != null && barArc != null;

RenderAll();
}

/// <summary>
/// Gets or sets the thickness of the circular ouline and segment
/// </summary>
public double Thickness
{
get { return (double)GetValue(ThicknessProperty); }
set { SetValue(ThicknessProperty, value); }
}

/// <summary>
/// Identifies the Thickness dependency property
/// </summary>
public static readonly DependencyProperty ThicknessProperty = DependencyProperty.Register(nameof(Thickness), typeof(double), typeof(RadialProgressBar), new PropertyMetadata(0.0, ThicknessChangedHandler));

/// <summary>
/// Gets or sets the color of the circular ouline on which the segment is drawn
/// </summary>
public Brush Outline
{
get { return (Brush)GetValue(OutlineProperty); }
set { SetValue(OutlineProperty, value); }
}

/// <summary>
/// Identifies the Outline dependency property
/// </summary>
public static readonly DependencyProperty OutlineProperty = DependencyProperty.Register(nameof(Outline), typeof(Brush), typeof(RadialProgressBar), new PropertyMetadata(new SolidColorBrush(Windows.UI.Colors.Transparent)));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it make sense to use the same property names as ProgressBar for the Background color? In other words, wondering if this property is needed?


/// <summary>
/// Initializes a new instance of the <see cref="RadialProgressBar"/> class.
/// Create a default circular progress bar
/// </summary>
public RadialProgressBar()
{
DefaultStyleKey = typeof(RadialProgressBar);
SizeChanged += SizeChangedHandler;
}

// Render outline and progress segment when thickness is changed
private static void ThicknessChangedHandler(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var sender = d as RadialProgressBar;
sender.RenderAll();
}

// Render outline and progress segment when control is resized.
private void SizeChangedHandler(object sender, SizeChangedEventArgs e)
{
var self = sender as RadialProgressBar;
self.RenderAll();
}

private double ComputeNormalizedRange()
{
var range = Maximum - Minimum;
var delta = Value - Minimum;
var output = range == 0.0 ? 0.0 : delta / range;
output = Math.Min(Math.Max(0.0, output), 0.9999);
return output;
}

// Compute size of ellipse so that the outer edge touches the bounding rectangle
private Size ComputeEllipseSize()
{
var safeThickness = Math.Max(Thickness, 0.0);
var width = Math.Max((ActualWidth - safeThickness) / 2.0, 0.0);
var height = Math.Max((ActualHeight - safeThickness) / 2.0, 0.0);
return new Size(width, height);
}

// Render the segment representing progress ratio.
private void RenderSegment()
{
if (!allTemplatePartsDefined)
{
return;
}

var normalizedRange = ComputeNormalizedRange();

var angle = 2 * Math.PI * normalizedRange;
var size = ComputeEllipseSize();
var translationFactor = Math.Max(Thickness / 2.0, 0.0);

double x = (Math.Sin(angle) * size.Width) + size.Width + translationFactor;
double y = (((Math.Cos(angle) * size.Height) - size.Height) * -1) + translationFactor;

barArc.IsLargeArc = angle >= Math.PI;
barArc.Point = new Point(x, y);
}

// Render the progress segment and the loop outline. Needs to run when control is resized or retemplated
private void RenderAll()
{
if (!allTemplatePartsDefined)
{
return;
}

var size = ComputeEllipseSize();
var segmentWidth = size.Width;
var translationFactor = Math.Max(Thickness / 2.0, 0.0);

outlineFigure.StartPoint = barFigure.StartPoint = new Point(segmentWidth + translationFactor, translationFactor);
outlineArc.Size = barArc.Size = new Size(segmentWidth, size.Height);
outlineArc.Point = new Point(segmentWidth + translationFactor - 0.05, translationFactor);

RenderSegment();
}
}
}
Loading