зеркало из https://github.com/AvaloniaUI/Avalonia.git
Merge pull request #1175 from jp2masa/progressbar
Added Orientation and IsIndeterminate properties to ProgressBar
This commit is contained in:
Коммит
9d5a0be23e
|
@ -69,6 +69,9 @@
|
|||
<EmbeddedResource Include="Pages\MenuPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\ProgressBarPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
<EmbeddedResource Include="Pages\RadioButtonPage.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</EmbeddedResource>
|
||||
|
@ -131,6 +134,9 @@
|
|||
<Compile Include="Pages\MenuPage.xaml.cs">
|
||||
<DependentUpon>MenuPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\ProgressBarPage.xaml.cs">
|
||||
<DependentUpon>ProgressBarPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Pages\RadioButtonPage.xaml.cs">
|
||||
<DependentUpon>RadioButtonPage.xaml</DependentUpon>
|
||||
</Compile>
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
<TabItem Header="Image"><pages:ImagePage/></TabItem>
|
||||
<TabItem Header="LayoutTransformControl"><pages:LayoutTransformControlPage/></TabItem>
|
||||
<TabItem Header="Menu"><pages:MenuPage/></TabItem>
|
||||
<TabItem Header="ProgressBar"><pages:ProgressBarPage/></TabItem>
|
||||
<TabItem Header="RadioButton"><pages:RadioButtonPage/></TabItem>
|
||||
<TabItem Header="Slider"><pages:SliderPage/></TabItem>
|
||||
<TabItem Header="TextBox"><pages:TextBoxPage/></TabItem>
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
<UserControl xmlns="https://github.com/avaloniaui">
|
||||
<StackPanel Orientation="Vertical" Gap="4">
|
||||
<TextBlock Classes="h1">ProgressBar</TextBlock>
|
||||
<TextBlock Classes="h2">A progress bar control</TextBlock>
|
||||
|
||||
<StackPanel>
|
||||
<StackPanel Orientation="Horizontal"
|
||||
Margin="0,16,0,0"
|
||||
HorizontalAlignment="Center"
|
||||
Gap="16">
|
||||
<StackPanel Gap="16">
|
||||
<ProgressBar Value="{Binding #hprogress.Value}" />
|
||||
<ProgressBar IsIndeterminate="True"/>
|
||||
</StackPanel>
|
||||
<ProgressBar Value="{Binding #vprogress.Value}" Orientation="Vertical" />
|
||||
<ProgressBar Orientation="Vertical" IsIndeterminate="True" />
|
||||
</StackPanel>
|
||||
<StackPanel Margin="16">
|
||||
<Slider Name="hprogress" Maximum="100" Value="40"/>
|
||||
<Slider Name="vprogress" Maximum="100" Value="60"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</UserControl>
|
|
@ -0,0 +1,18 @@
|
|||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace ControlCatalog.Pages
|
||||
{
|
||||
public class ProgressBarPage : UserControl
|
||||
{
|
||||
public ProgressBarPage()
|
||||
{
|
||||
this.InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
||||
namespace Avalonia.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines vertical or horizontal orientation.
|
||||
/// </summary>
|
||||
public enum Orientation
|
||||
{
|
||||
/// <summary>
|
||||
/// Horizontal orientation.
|
||||
/// </summary>
|
||||
Horizontal,
|
||||
|
||||
/// <summary>
|
||||
/// Vertical orientation.
|
||||
/// </summary>
|
||||
Vertical,
|
||||
}
|
||||
}
|
|
@ -30,7 +30,7 @@ namespace Avalonia.Controls.Primitives
|
|||
/// Defines the <see cref="Orientation"/> property.
|
||||
/// </summary>
|
||||
public static readonly StyledProperty<Orientation> OrientationProperty =
|
||||
AvaloniaProperty.Register<ScrollBar, Orientation>(nameof(Orientation));
|
||||
AvaloniaProperty.Register<ScrollBar, Orientation>(nameof(Orientation), Orientation.Vertical);
|
||||
|
||||
private Button _lineUpButton;
|
||||
private Button _lineDownButton;
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
// Copyright (c) The Avalonia Project. All rights reserved.
|
||||
// Licensed under the MIT license. See licence.md file in the project root for full license information.
|
||||
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
|
||||
using Avalonia.Animation;
|
||||
using Avalonia.Controls.Primitives;
|
||||
using Avalonia.Controls.Templates;
|
||||
using Avalonia.Layout;
|
||||
|
||||
namespace Avalonia.Controls
|
||||
{
|
||||
|
@ -11,11 +15,38 @@ namespace Avalonia.Controls
|
|||
/// </summary>
|
||||
public class ProgressBar : RangeBase
|
||||
{
|
||||
public static readonly StyledProperty<bool> IsIndeterminateProperty =
|
||||
AvaloniaProperty.Register<ProgressBar, bool>(nameof(IsIndeterminate));
|
||||
|
||||
public static readonly StyledProperty<Orientation> OrientationProperty =
|
||||
AvaloniaProperty.Register<ProgressBar, Orientation>(nameof(Orientation), Orientation.Horizontal);
|
||||
|
||||
private Border _indicator;
|
||||
private IndeterminateAnimation _indeterminateAnimation;
|
||||
|
||||
static ProgressBar()
|
||||
{
|
||||
ValueProperty.Changed.AddClassHandler<ProgressBar>(x => x.ValueChanged);
|
||||
|
||||
HorizontalAlignmentProperty.OverrideDefaultValue<ProgressBar>(HorizontalAlignment.Left);
|
||||
VerticalAlignmentProperty.OverrideDefaultValue<ProgressBar>(VerticalAlignment.Top);
|
||||
|
||||
IsIndeterminateProperty.Changed.AddClassHandler<ProgressBar>(
|
||||
(p, e) => { if (p._indicator != null) p.UpdateIsIndeterminate((bool)e.NewValue); });
|
||||
OrientationProperty.Changed.AddClassHandler<ProgressBar>(
|
||||
(p, e) => { if (p._indicator != null) p.UpdateOrientation((Orientation)e.NewValue); });
|
||||
}
|
||||
|
||||
public bool IsIndeterminate
|
||||
{
|
||||
get => GetValue(IsIndeterminateProperty);
|
||||
set => SetValue(IsIndeterminateProperty, value);
|
||||
}
|
||||
|
||||
public Orientation Orientation
|
||||
{
|
||||
get => GetValue(OrientationProperty);
|
||||
set => SetValue(OrientationProperty, value);
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
|
@ -29,21 +60,123 @@ namespace Avalonia.Controls
|
|||
protected override void OnTemplateApplied(TemplateAppliedEventArgs e)
|
||||
{
|
||||
_indicator = e.NameScope.Get<Border>("PART_Indicator");
|
||||
|
||||
UpdateIndicator(Bounds.Size);
|
||||
UpdateOrientation(Orientation);
|
||||
UpdateIsIndeterminate(IsIndeterminate);
|
||||
}
|
||||
|
||||
private void UpdateIndicator(Size bounds)
|
||||
{
|
||||
if (_indicator != null)
|
||||
{
|
||||
double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum);
|
||||
_indicator.Width = bounds.Width * percent;
|
||||
if (IsIndeterminate)
|
||||
{
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
_indicator.Width = bounds.Width / 5.0;
|
||||
else
|
||||
_indicator.Height = bounds.Height / 5.0;
|
||||
}
|
||||
else
|
||||
{
|
||||
double percent = Maximum == Minimum ? 1.0 : (Value - Minimum) / (Maximum - Minimum);
|
||||
|
||||
if (Orientation == Orientation.Horizontal)
|
||||
_indicator.Width = bounds.Width * percent;
|
||||
else
|
||||
_indicator.Height = bounds.Height * percent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateOrientation(Orientation orientation)
|
||||
{
|
||||
if (orientation == Orientation.Horizontal)
|
||||
{
|
||||
MinHeight = 14;
|
||||
MinWidth = 200;
|
||||
|
||||
_indicator.HorizontalAlignment = HorizontalAlignment.Left;
|
||||
_indicator.VerticalAlignment = VerticalAlignment.Stretch;
|
||||
}
|
||||
else
|
||||
{
|
||||
MinHeight = 200;
|
||||
MinWidth = 14;
|
||||
|
||||
_indicator.HorizontalAlignment = HorizontalAlignment.Stretch;
|
||||
_indicator.VerticalAlignment = VerticalAlignment.Bottom;
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateIsIndeterminate(bool isIndeterminate)
|
||||
{
|
||||
if (isIndeterminate)
|
||||
if (_indeterminateAnimation == null || _indeterminateAnimation.Disposed)
|
||||
_indeterminateAnimation = IndeterminateAnimation.StartAnimation(this);
|
||||
else
|
||||
_indeterminateAnimation?.Dispose();
|
||||
}
|
||||
|
||||
private void ValueChanged(AvaloniaPropertyChangedEventArgs e)
|
||||
{
|
||||
UpdateIndicator(Bounds.Size);
|
||||
}
|
||||
|
||||
private class IndeterminateAnimation : IDisposable
|
||||
{
|
||||
private WeakReference<ProgressBar> _progressBar;
|
||||
private IDisposable _indeterminateBindSubscription;
|
||||
private TimeSpan _startTime;
|
||||
private bool _disposed;
|
||||
|
||||
public bool Disposed => _disposed;
|
||||
|
||||
private IndeterminateAnimation(ProgressBar progressBar)
|
||||
{
|
||||
_progressBar = new WeakReference<ProgressBar>(progressBar);
|
||||
_startTime = Animate.Stopwatch.Elapsed;
|
||||
_indeterminateBindSubscription = Animate.Timer.TakeWhile(x => (x - _startTime).TotalSeconds <= 4.0)
|
||||
.Select(GetAnimationRect)
|
||||
.Finally(() => _startTime = Animate.Stopwatch.Elapsed)
|
||||
.Repeat()
|
||||
.Subscribe(AnimationTick);
|
||||
}
|
||||
|
||||
public static IndeterminateAnimation StartAnimation(ProgressBar progressBar)
|
||||
{
|
||||
return new IndeterminateAnimation(progressBar);
|
||||
}
|
||||
|
||||
private Rect GetAnimationRect(TimeSpan time)
|
||||
{
|
||||
if (_progressBar.TryGetTarget(out var progressBar))
|
||||
{
|
||||
if (progressBar.Orientation == Orientation.Horizontal)
|
||||
return new Rect(-progressBar._indicator.Width - 5 + (time - _startTime).TotalSeconds / 4.0 * (progressBar.Bounds.Width + progressBar._indicator.Width + 10), 0, progressBar._indicator.Bounds.Width, progressBar._indicator.Bounds.Height);
|
||||
else
|
||||
return new Rect(0, progressBar.Bounds.Height + 5 - (time - _startTime).TotalSeconds / 4.0 * (progressBar.Bounds.Height + progressBar._indicator.Height + 10), progressBar._indicator.Bounds.Width, progressBar._indicator.Bounds.Height);
|
||||
}
|
||||
else
|
||||
{
|
||||
_indeterminateBindSubscription.Dispose();
|
||||
return Rect.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
private void AnimationTick(Rect rect)
|
||||
{
|
||||
if (_progressBar.TryGetTarget(out var progressBar))
|
||||
progressBar._indicator.Arrange(rect);
|
||||
else
|
||||
_indeterminateBindSubscription.Dispose();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_indeterminateBindSubscription?.Dispose();
|
||||
_disposed = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,22 +6,6 @@ using Avalonia.Input;
|
|||
|
||||
namespace Avalonia.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Defines vertical or horizontal orientation.
|
||||
/// </summary>
|
||||
public enum Orientation
|
||||
{
|
||||
/// <summary>
|
||||
/// Vertical orientation.
|
||||
/// </summary>
|
||||
Vertical,
|
||||
|
||||
/// <summary>
|
||||
/// Horizontal orientation.
|
||||
/// </summary>
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A panel which lays out its children horizontally or vertically.
|
||||
/// </summary>
|
||||
|
@ -37,7 +21,7 @@ namespace Avalonia.Controls
|
|||
/// Defines the <see cref="Orientation"/> property.
|
||||
/// </summary>
|
||||
public static readonly StyledProperty<Orientation> OrientationProperty =
|
||||
AvaloniaProperty.Register<StackPanel, Orientation>(nameof(Orientation));
|
||||
AvaloniaProperty.Register<StackPanel, Orientation>(nameof(Orientation), Orientation.Vertical);
|
||||
|
||||
/// <summary>
|
||||
/// Initializes static members of the <see cref="StackPanel"/> class.
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
<Style xmlns="https://github.com/avaloniaui" Selector="ProgressBar">
|
||||
<Setter Property="Background" Value="{DynamicResource ThemeAccentBrush4}"/>
|
||||
<Setter Property="Foreground" Value="{DynamicResource ThemeAccentBrush}"/>
|
||||
<Setter Property="MinHeight" Value="14"/>
|
||||
<Setter Property="MinWidth" Value="200"/>
|
||||
<Setter Property="Template">
|
||||
<ControlTemplate>
|
||||
<Border Background="{TemplateBinding Background}"
|
||||
|
@ -14,8 +12,7 @@
|
|||
BorderBrush="{TemplateBinding Background}"/>
|
||||
<Border Name="PART_Indicator"
|
||||
BorderThickness="1"
|
||||
Background="{TemplateBinding Foreground}"
|
||||
HorizontalAlignment="Left"/>
|
||||
Background="{TemplateBinding Foreground}"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</ControlTemplate>
|
||||
|
|
Загрузка…
Ссылка в новой задаче