diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md index 78b9cff039..acff8cc117 100644 --- a/.github/PULL_REQUEST_TEMPLATE.md +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -1,18 +1,18 @@ ## What does the pull request do? + -Give a bit of background on the PR here, together with links to with related issues etc. ## What is the current behavior? + -If the PR is a fix, describe the current incorrect behavior, otherwise delete this section. ## What is the updated/expected behavior with this PR? + -Describe how to test the PR. ## How was the solution implemented (if it's not obvious)? + -Include any information that might be of use to a reviewer here. ## Checklist @@ -21,12 +21,11 @@ Include any information that might be of use to a reviewer here. - [ ] Consider submitting a PR to https://github.com/AvaloniaUI/Avaloniaui.net with user documentation ## Breaking changes + -List any breaking changes here. When the PR is merged please add an entry to https://github.com/AvaloniaUI/Avalonia/wiki/Breaking-Changes ## Fixed issues - -If the pull request fixes issue(s) list them like this: - + diff --git a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs index 6f57dfbf13..5fcdf76c0f 100644 --- a/src/Avalonia.Base/AvaloniaPropertyRegistry.cs +++ b/src/Avalonia.Base/AvaloniaPropertyRegistry.cs @@ -13,8 +13,8 @@ namespace Avalonia /// public class AvaloniaPropertyRegistry { - private readonly List _properties = - new List(); + private readonly Dictionary _properties = + new Dictionary(); private readonly Dictionary> _registered = new Dictionary>(); private readonly Dictionary> _attached = @@ -33,7 +33,7 @@ namespace Avalonia /// /// Gets a list of all registered properties. /// - internal IReadOnlyList Properties => _properties; + internal IReadOnlyCollection Properties => _properties.Values; /// /// Gets all non-attached s registered on a type. @@ -220,7 +220,11 @@ namespace Avalonia inner.Add(property.Id, property); } - _properties.Add(property); + if (!_properties.ContainsKey(property.Id)) + { + _properties.Add(property.Id, property); + } + _registeredCache.Clear(); } diff --git a/src/Avalonia.Base/Data/Core/BindingExpression.cs b/src/Avalonia.Base/Data/Core/BindingExpression.cs index c4ffa839e0..f1717bde3b 100644 --- a/src/Avalonia.Base/Data/Core/BindingExpression.cs +++ b/src/Avalonia.Base/Data/Core/BindingExpression.cs @@ -177,7 +177,7 @@ namespace Avalonia.Data.Core protected override void Subscribed(IObserver observer, bool first) { - if (!first && _value != null && _value.TryGetTarget(out var val) == true) + if (!first && _value != null && _value.TryGetTarget(out var val)) { observer.OnNext(val); } diff --git a/src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs b/src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs index 22e5c952bf..66024236da 100644 --- a/src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs +++ b/src/Avalonia.Base/Utilities/AvaloniaResourcesIndex.cs @@ -4,6 +4,8 @@ using System.IO; using System.Runtime.CompilerServices; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; +using System.Xml.Linq; +using System.Linq; // ReSharper disable AssignNullToNotNullAttribute @@ -19,10 +21,20 @@ namespace Avalonia.Utilities { var ver = new BinaryReader(stream).ReadInt32(); if (ver > LastKnownVersion) - throw new Exception("Resources index format version is not known"); - var index = (AvaloniaResourcesIndex) - new DataContractSerializer(typeof(AvaloniaResourcesIndex)).ReadObject(stream); - return index.Entries; + throw new Exception("Resources index format version is not known"); + + var assetDoc = XDocument.Load(stream); + XNamespace assetNs = assetDoc.Root.Attribute("xmlns").Value; + List entries= + (from entry in assetDoc.Root.Element(assetNs + "Entries").Elements(assetNs + "AvaloniaResourcesIndexEntry") + select new AvaloniaResourcesIndexEntry + { + Path = entry.Element(assetNs + "Path").Value, + Offset = int.Parse(entry.Element(assetNs + "Offset").Value), + Size = int.Parse(entry.Element(assetNs + "Size").Value) + }).ToList(); + + return entries; } public static void Write(Stream stream, List entries) diff --git a/src/Avalonia.Controls/AutoCompleteBox.cs b/src/Avalonia.Controls/AutoCompleteBox.cs index 1bc402bc2f..b054804c86 100644 --- a/src/Avalonia.Controls/AutoCompleteBox.cs +++ b/src/Avalonia.Controls/AutoCompleteBox.cs @@ -1893,7 +1893,7 @@ namespace Avalonia.Controls { bool callTextChanged = false; // Update the Text dependency property - if ((userInitiated == null || userInitiated == true) && Text != value) + if ((userInitiated ?? true) && Text != value) { _ignoreTextPropertyChange++; Text = value; diff --git a/src/Avalonia.Controls/MenuItem.cs b/src/Avalonia.Controls/MenuItem.cs index 055d49fb0b..99e00ce72e 100644 --- a/src/Avalonia.Controls/MenuItem.cs +++ b/src/Avalonia.Controls/MenuItem.cs @@ -421,7 +421,7 @@ namespace Avalonia.Controls } /// - /// Called when the property changes. + /// Called when the property changes. /// /// The property change event. private void HeaderChanged(AvaloniaPropertyChangedEventArgs e) diff --git a/src/Avalonia.Controls/PixelPointEventArgs.cs b/src/Avalonia.Controls/PixelPointEventArgs.cs index 55a3d5601f..2456d0aea4 100644 --- a/src/Avalonia.Controls/PixelPointEventArgs.cs +++ b/src/Avalonia.Controls/PixelPointEventArgs.cs @@ -13,7 +13,7 @@ namespace Avalonia.Controls /// /// Initializes a new instance of the class. /// - /// The data. + /// The data. public PixelPointEventArgs(PixelPoint point) { Point = point; diff --git a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs index c05c1672f8..30330ef9ac 100644 --- a/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs +++ b/src/Avalonia.Controls/Presenters/ScrollContentPresenter.cs @@ -285,7 +285,7 @@ namespace Avalonia.Controls.Presenters { scrollable.InvalidateScroll = () => UpdateFromScrollable(scrollable); - if (scrollable.IsLogicalScrollEnabled == true) + if (scrollable.IsLogicalScrollEnabled) { _logicalScrollSubscription = new CompositeDisposable( this.GetObservable(CanHorizontallyScrollProperty) diff --git a/src/Avalonia.Controls/Shapes/Shape.cs b/src/Avalonia.Controls/Shapes/Shape.cs index f77c43acd0..0387328a46 100644 --- a/src/Avalonia.Controls/Shapes/Shape.cs +++ b/src/Avalonia.Controls/Shapes/Shape.cs @@ -20,7 +20,10 @@ namespace Avalonia.Controls.Shapes AvaloniaProperty.Register(nameof(Stroke)); public static readonly StyledProperty> StrokeDashArrayProperty = - AvaloniaProperty.Register>("StrokeDashArray"); + AvaloniaProperty.Register>(nameof(StrokeDashArray)); + + public static readonly StyledProperty StrokeDashOffsetProperty = + AvaloniaProperty.Register(nameof(StrokeDashOffset)); public static readonly StyledProperty StrokeThicknessProperty = AvaloniaProperty.Register(nameof(StrokeThickness)); @@ -103,6 +106,12 @@ namespace Avalonia.Controls.Shapes get { return GetValue(StrokeDashArrayProperty); } set { SetValue(StrokeDashArrayProperty, value); } } + + public double StrokeDashOffset + { + get { return GetValue(StrokeDashOffsetProperty); } + set { SetValue(StrokeDashOffsetProperty, value); } + } public double StrokeThickness { @@ -124,7 +133,7 @@ namespace Avalonia.Controls.Shapes if (geometry != null) { - var pen = new Pen(Stroke, StrokeThickness, new DashStyle(StrokeDashArray), + var pen = new Pen(Stroke, StrokeThickness, new DashStyle(StrokeDashArray, StrokeDashOffset), StrokeDashCap, StrokeStartLineCap, StrokeEndLineCap, StrokeJoin); context.DrawGeometry(Fill, pen, geometry); } diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index 60e624948e..3bc5e92fb4 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -255,15 +255,19 @@ namespace Avalonia.Rendering } var (scene, updated) = UpdateRenderLayersAndConsumeSceneIfNeeded(GetContext); + using (scene) { - var overlay = DrawDirtyRects || DrawFps; - if (DrawDirtyRects) - _dirtyRectsDisplay.Tick(); - if (overlay) - RenderOverlay(scene.Item, GetContext()); - if (updated || forceComposite || overlay) - RenderComposite(scene.Item, GetContext()); + if (scene?.Item != null) + { + var overlay = DrawDirtyRects || DrawFps; + if (DrawDirtyRects) + _dirtyRectsDisplay.Tick(); + if (overlay) + RenderOverlay(scene.Item, GetContext()); + if (updated || forceComposite || overlay) + RenderComposite(scene.Item, GetContext()); + } } } finally diff --git a/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs b/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs index 159c3cd0fa..2fb8e84a2e 100644 --- a/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs +++ b/src/Avalonia.Visuals/Rendering/SceneGraph/VisualNode.cs @@ -236,7 +236,7 @@ namespace Avalonia.Rendering.SceneGraph { foreach (var operation in DrawOperations) { - if (operation.Item.HitTest(p) == true) + if (operation.Item.HitTest(p)) { return true; } diff --git a/src/Avalonia.X11/X11Screens.cs b/src/Avalonia.X11/X11Screens.cs index f2a0520c10..6bfc8779da 100644 --- a/src/Avalonia.X11/X11Screens.cs +++ b/src/Avalonia.X11/X11Screens.cs @@ -218,6 +218,7 @@ namespace Avalonia.X11 class X11Screen { + private const int FullHDWidth = 1920; public bool Primary { get; } public string Name { get; set; } public PixelRect Bounds { get; set; } @@ -247,6 +248,6 @@ namespace Avalonia.X11 } public static double GuessPixelDensity(double pixelWidth, double mmWidth) - => Math.Max(1, Math.Round(pixelWidth / mmWidth * 25.4 / 96)); + => pixelWidth <= FullHDWidth ? 1 : Math.Max(1, Math.Round(pixelWidth / mmWidth * 25.4 / 96)); } } diff --git a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs index a825deeae3..2720e674cc 100644 --- a/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs +++ b/src/Markup/Avalonia.Markup.Xaml/AvaloniaXamlLoader.cs @@ -13,6 +13,8 @@ using System.Reflection; using System.Runtime.Serialization; using System.Runtime.Serialization.Json; using System.Text; +using System.Xml.Linq; +using System.Linq; namespace Avalonia.Markup.Xaml { @@ -240,15 +242,21 @@ namespace Avalonia.Markup.Xaml { using (var xamlInfoStream = assetLocator.Open(xamlInfoUri)) { - var xamlInfo = (AvaloniaResourceXamlInfo)s_xamlInfoSerializer.ReadObject(xamlInfoStream); - if (xamlInfo.ClassToResourcePathIndex.TryGetValue(typeName, out var rv) == true) + var assetDoc = XDocument.Load(xamlInfoStream); + XNamespace assetNs = assetDoc.Root.Attribute("xmlns").Value; + XNamespace arrayNs = "http://schemas.microsoft.com/2003/10/Serialization/Arrays"; + Dictionary xamlInfo = + assetDoc.Root.Element(assetNs + "ClassToResourcePathIndex").Elements(arrayNs + "KeyValueOfstringstring") + .ToDictionary(entry =>entry.Element(arrayNs + "Key").Value, + entry => entry.Element(arrayNs + "Value").Value); + + if (xamlInfo.TryGetValue(typeName, out var rv)) { yield return new Uri($"avares://{asm}{rv}"); yield break; } } - } - + } yield return new Uri("resm:" + typeName + ".xaml?assembly=" + asm); yield return new Uri("resm:" + typeName + ".paml?assembly=" + asm); diff --git a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs index 8220b7d6e7..d11319114f 100644 --- a/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs +++ b/tests/Avalonia.Base.UnitTests/AvaloniaPropertyRegistryTests.cs @@ -27,6 +27,7 @@ namespace Avalonia.Base.UnitTests var property = new AttachedProperty("test", typeof(object), metadata, true); registry.Register(typeof(object), property); registry.RegisterAttached(typeof(AvaloniaPropertyRegistryTests), property); + property.AddOwner(); Assert.Equal(1, registry.Properties.Count); } @@ -150,5 +151,9 @@ namespace Avalonia.Base.UnitTests private class AttachedOwner2 : AttachedOwner { } + + private class Class4 : AvaloniaObject + { + } } }