Browse Source

Make DashStyle.Dashes an AvaloniaList.

So that it can be parsed from XAML and changes can be made.
pull/5092/head
Steven Kirk 6 years ago
parent
commit
d99512a785
  1. 75
      src/Avalonia.Visuals/Media/DashStyle.cs
  2. 18
      tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs

75
src/Avalonia.Visuals/Media/DashStyle.cs

@ -1,11 +1,14 @@
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using Avalonia.Animation;
using Avalonia.Collections;
using Avalonia.Media.Immutable;
#nullable enable
namespace Avalonia.Media namespace Avalonia.Media
{ {
using System;
using System.Collections.Generic;
using System.Linq;
using Avalonia.Animation;
using Avalonia.Media.Immutable;
/// <summary> /// <summary>
/// Represents the sequence of dashes and gaps that will be applied by a <see cref="Pen"/>. /// Represents the sequence of dashes and gaps that will be applied by a <see cref="Pen"/>.
/// </summary> /// </summary>
@ -14,8 +17,8 @@ namespace Avalonia.Media
/// <summary> /// <summary>
/// Defines the <see cref="Dashes"/> property. /// Defines the <see cref="Dashes"/> property.
/// </summary> /// </summary>
public static readonly StyledProperty<IReadOnlyList<double>> DashesProperty = public static readonly StyledProperty<AvaloniaList<double>> DashesProperty =
AvaloniaProperty.Register<DashStyle, IReadOnlyList<double>>(nameof(Dashes)); AvaloniaProperty.Register<DashStyle, AvaloniaList<double>>(nameof(Dashes));
/// <summary> /// <summary>
/// Defines the <see cref="Offset"/> property. /// Defines the <see cref="Offset"/> property.
@ -23,10 +26,10 @@ namespace Avalonia.Media
public static readonly StyledProperty<double> OffsetProperty = public static readonly StyledProperty<double> OffsetProperty =
AvaloniaProperty.Register<DashStyle, double>(nameof(Offset)); AvaloniaProperty.Register<DashStyle, double>(nameof(Offset));
private static ImmutableDashStyle s_dash; private static ImmutableDashStyle? s_dash;
private static ImmutableDashStyle s_dot; private static ImmutableDashStyle? s_dot;
private static ImmutableDashStyle s_dashDot; private static ImmutableDashStyle? s_dashDot;
private static ImmutableDashStyle s_dashDotDot; private static ImmutableDashStyle? s_dashDotDot;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DashStyle"/> class. /// Initializes a new instance of the <see cref="DashStyle"/> class.
@ -41,9 +44,9 @@ namespace Avalonia.Media
/// </summary> /// </summary>
/// <param name="dashes">The dashes collection.</param> /// <param name="dashes">The dashes collection.</param>
/// <param name="offset">The dash sequence offset.</param> /// <param name="offset">The dash sequence offset.</param>
public DashStyle(IEnumerable<double> dashes, double offset) public DashStyle(IEnumerable<double>? dashes, double offset)
{ {
Dashes = (IReadOnlyList<double>)dashes?.ToList() ?? Array.Empty<double>(); Dashes = (dashes as AvaloniaList<double>) ?? new AvaloniaList<double>(dashes ?? Array.Empty<double>());
Offset = offset; Offset = offset;
} }
@ -61,31 +64,27 @@ namespace Avalonia.Media
/// <summary> /// <summary>
/// Represents a dashed <see cref="DashStyle"/>. /// Represents a dashed <see cref="DashStyle"/>.
/// </summary> /// </summary>
public static IDashStyle Dash => public static IDashStyle Dash => s_dash ??= new ImmutableDashStyle(new double[] { 2, 2 }, 1);
s_dash ?? (s_dash = new ImmutableDashStyle(new double[] { 2, 2 }, 1));
/// <summary> /// <summary>
/// Represents a dotted <see cref="DashStyle"/>. /// Represents a dotted <see cref="DashStyle"/>.
/// </summary> /// </summary>
public static IDashStyle Dot => public static IDashStyle Dot => s_dot ??= new ImmutableDashStyle(new double[] { 0, 2 }, 0);
s_dot ?? (s_dot = new ImmutableDashStyle(new double[] { 0, 2 }, 0));
/// <summary> /// <summary>
/// Represents a dashed dotted <see cref="DashStyle"/>. /// Represents a dashed dotted <see cref="DashStyle"/>.
/// </summary> /// </summary>
public static IDashStyle DashDot => public static IDashStyle DashDot => s_dashDot ??= new ImmutableDashStyle(new double[] { 2, 2, 0, 2 }, 1);
s_dashDot ?? (s_dashDot = new ImmutableDashStyle(new double[] { 2, 2, 0, 2 }, 1));
/// <summary> /// <summary>
/// Represents a dashed double dotted <see cref="DashStyle"/>. /// Represents a dashed double dotted <see cref="DashStyle"/>.
/// </summary> /// </summary>
public static IDashStyle DashDotDot => public static IDashStyle DashDotDot => s_dashDotDot ??= new ImmutableDashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 1);
s_dashDotDot ?? (s_dashDotDot = new ImmutableDashStyle(new double[] { 2, 2, 0, 2, 0, 2 }, 1));
/// <summary> /// <summary>
/// Gets or sets the length of alternating dashes and gaps. /// Gets or sets the length of alternating dashes and gaps.
/// </summary> /// </summary>
public IReadOnlyList<double> Dashes public AvaloniaList<double> Dashes
{ {
get => GetValue(DashesProperty); get => GetValue(DashesProperty);
set => SetValue(DashesProperty, value); set => SetValue(DashesProperty, value);
@ -100,15 +99,43 @@ namespace Avalonia.Media
set => SetValue(OffsetProperty, value); set => SetValue(OffsetProperty, value);
} }
IReadOnlyList<double> IDashStyle.Dashes => Dashes;
/// <summary> /// <summary>
/// Raised when the dash style changes. /// Raised when the dash style changes.
/// </summary> /// </summary>
public event EventHandler Invalidated; public event EventHandler? Invalidated;
/// <summary> /// <summary>
/// Returns an immutable clone of the <see cref="DashStyle"/>. /// Returns an immutable clone of the <see cref="DashStyle"/>.
/// </summary> /// </summary>
/// <returns></returns> /// <returns></returns>
public ImmutableDashStyle ToImmutable() => new ImmutableDashStyle(Dashes, Offset); public ImmutableDashStyle ToImmutable() => new ImmutableDashStyle(Dashes, Offset);
protected override void OnPropertyChanged<T>(AvaloniaPropertyChangedEventArgs<T> change)
{
base.OnPropertyChanged(change);
if (change.Property == DashesProperty)
{
var oldValue = change.OldValue.GetValueOrDefault<AvaloniaList<double>>();
var newValue = change.NewValue.GetValueOrDefault<AvaloniaList<double>>();
if (oldValue is object)
{
oldValue.CollectionChanged -= DashesChanged;
}
if (newValue is object)
{
newValue.CollectionChanged += DashesChanged;
}
}
}
private void DashesChanged(object sender, NotifyCollectionChangedEventArgs e)
{
Invalidated?.Invoke(this, e);
}
} }
} }

18
tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs

@ -1,4 +1,5 @@
using Avalonia.Media; using Avalonia.Collections;
using Avalonia.Media;
using Avalonia.Media.Immutable; using Avalonia.Media.Immutable;
using Xunit; using Xunit;
@ -39,7 +40,20 @@ namespace Avalonia.Visuals.UnitTests.Media
var raised = false; var raised = false;
target.Invalidated += (s, e) => raised = true; target.Invalidated += (s, e) => raised = true;
dashes.Dashes = new[] { 0.1, 0.2 }; dashes.Dashes = new AvaloniaList<double> { 0.1, 0.2 };
Assert.True(raised);
}
[Fact]
public void Adding_DashStyle_Dashes_Raises_Invalidated()
{
var dashes = new DashStyle();
var target = new Pen { DashStyle = dashes };
var raised = false;
target.Invalidated += (s, e) => raised = true;
dashes.Dashes.Add(0.3);
Assert.True(raised); Assert.True(raised);
} }

Loading…
Cancel
Save