diff --git a/src/Avalonia.Visuals/Media/DashStyle.cs b/src/Avalonia.Visuals/Media/DashStyle.cs
index 7784c73736..bd81cb1d03 100644
--- a/src/Avalonia.Visuals/Media/DashStyle.cs
+++ b/src/Avalonia.Visuals/Media/DashStyle.cs
@@ -9,7 +9,7 @@ namespace Avalonia.Media
///
/// Represents the sequence of dashes and gaps that will be applied by a .
///
- public class DashStyle : Animatable, IDashStyle, IAffectsRender
+ public class DashStyle : Animatable, IDashStyle, IAffectsRender, IEquatable
{
///
/// Defines the property.
@@ -105,10 +105,64 @@ namespace Avalonia.Media
///
public event EventHandler Invalidated;
+ ///
+ public override bool Equals(object obj) => DashEquals(this, obj as IDashStyle);
+
+ ///
+ public bool Equals(IDashStyle other) => DashEquals(this, other);
+
+ ///
+ public override int GetHashCode() => GetHashCode(this);
+
///
/// Returns an immutable clone of the .
///
///
public ImmutableDashStyle ToImmutable() => new ImmutableDashStyle(Dashes, Offset);
+
+ internal static bool DashEquals(IDashStyle a, IDashStyle b)
+ {
+ if (ReferenceEquals(a, b))
+ {
+ return true;
+ }
+ else if ((a is null && !(b is null)) || (b is null && !(a is null)))
+ {
+ return false;
+ }
+
+ if (a.Offset != b.Offset)
+ {
+ return false;
+ }
+
+ if (ReferenceEquals(a.Dashes, b.Dashes))
+ {
+ return true;
+ }
+
+ if ((a.Dashes is null && !(b.Dashes is null)) || (b.Dashes is null && !(a.Dashes is null)))
+ {
+ return false;
+ }
+
+ return a.Dashes.SequenceEqual(b.Dashes);
+ }
+
+ internal static int GetHashCode(IDashStyle style)
+ {
+ var hashCode = 717868523;
+ hashCode = hashCode * -1521134295 + style.Offset.GetHashCode();
+
+ if (style.Dashes != null)
+ {
+ foreach (var i in style.Dashes)
+ {
+ hashCode = hashCode * -1521134295 + i.GetHashCode();
+ }
+ }
+
+ return hashCode;
+ }
}
}
diff --git a/src/Avalonia.Visuals/Media/Immutable/ImmutableDashStyle.cs b/src/Avalonia.Visuals/Media/Immutable/ImmutableDashStyle.cs
index a40682babd..65e27bf9b5 100644
--- a/src/Avalonia.Visuals/Media/Immutable/ImmutableDashStyle.cs
+++ b/src/Avalonia.Visuals/Media/Immutable/ImmutableDashStyle.cs
@@ -8,7 +8,7 @@ namespace Avalonia.Media.Immutable
/// Represents the sequence of dashes and gaps that will be applied by an
/// .
///
- public class ImmutableDashStyle : IDashStyle
+ public class ImmutableDashStyle : IDashStyle, IEquatable
{
///
/// Initializes a new instance of the class.
@@ -26,5 +26,15 @@ namespace Avalonia.Media.Immutable
///
public double Offset { get; }
+
+ ///
+ public override bool Equals(object obj) => DashStyle.DashEquals(this, obj as IDashStyle);
+
+ ///
+ public bool Equals(IDashStyle other) => DashStyle.DashEquals(this, other);
+
+ ///
+ public override int GetHashCode() => DashStyle.GetHashCode(this);
+
}
}
diff --git a/tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs b/tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs
index 70b4281083..d5601c7497 100644
--- a/tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs
+++ b/tests/Avalonia.Visuals.UnitTests/Media/PenTests.cs
@@ -65,5 +65,27 @@ namespace Avalonia.Visuals.UnitTests.Media
Assert.True(Equals(target1, target2));
}
+
+ [Fact]
+ public void Equality_Is_Implemented_Between_Mutable_And_Immutable_DashStyles()
+ {
+ var brush = new SolidColorBrush(Colors.Red);
+ var target1 = new Pen(
+ brush: brush,
+ thickness: 2,
+ dashStyle: new DashStyle(new[] { 0.1, 0.2 }, 5),
+ lineCap: PenLineCap.Round,
+ lineJoin: PenLineJoin.Round,
+ miterLimit: 21);
+ var target2 = new ImmutablePen(
+ brush: brush,
+ thickness: 2,
+ dashStyle: new ImmutableDashStyle(new[] { 0.1, 0.2 }, 5),
+ lineCap: PenLineCap.Round,
+ lineJoin: PenLineJoin.Round,
+ miterLimit: 21);
+
+ Assert.True(Equals(target1, target2));
+ }
}
}