From da38b72a35149bc83fe4fb5acb1d828320baccfe Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 20 Jul 2021 15:17:35 +0200 Subject: [PATCH 001/305] fixes(DevTools): Renamed Type as AssignedType --- .../Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs | 8 ++++---- .../Diagnostics/ViewModels/ClrPropertyViewModel.cs | 6 +++--- .../Diagnostics/ViewModels/PropertyViewModel.cs | 2 +- .../Diagnostics/Views/ControlDetailsView.xaml | 2 +- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs index e4c4ca6115..6bd26e39d6 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs @@ -3,7 +3,7 @@ namespace Avalonia.Diagnostics.ViewModels internal class AvaloniaPropertyViewModel : PropertyViewModel { private readonly AvaloniaObject _target; - private string _type; + private string _assignedType; private object? _value; private string _priority; private string _group; @@ -32,7 +32,7 @@ namespace Avalonia.Diagnostics.ViewModels public override string Priority => _priority; - public override string Type => _type; + public override string AssignedType => _assignedType; public override string Value { @@ -56,7 +56,7 @@ namespace Avalonia.Diagnostics.ViewModels if (Property.IsDirect) { RaiseAndSetIfChanged(ref _value, _target.GetValue(Property), nameof(Value)); - RaiseAndSetIfChanged(ref _type, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(Type)); + RaiseAndSetIfChanged(ref _assignedType, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(AssignedType)); RaiseAndSetIfChanged(ref _priority, "Direct", nameof(Priority)); _group = "Properties"; @@ -66,7 +66,7 @@ namespace Avalonia.Diagnostics.ViewModels var val = _target.GetDiagnostic(Property); RaiseAndSetIfChanged(ref _value, val?.Value, nameof(Value)); - RaiseAndSetIfChanged(ref _type, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(Type)); + RaiseAndSetIfChanged(ref _assignedType, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(AssignedType)); if (val != null) { diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs index 65626aeea5..b87d2b0b53 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs @@ -5,7 +5,7 @@ namespace Avalonia.Diagnostics.ViewModels internal class ClrPropertyViewModel : PropertyViewModel { private readonly object _target; - private string _type; + private string _assignedType; private object? _value; #nullable disable @@ -33,7 +33,7 @@ namespace Avalonia.Diagnostics.ViewModels public override string Name { get; } public override string Group => "CLR Properties"; - public override string Type => _type; + public override string AssignedType => _assignedType; public override string Value { @@ -60,7 +60,7 @@ namespace Avalonia.Diagnostics.ViewModels { var val = Property.GetValue(_target); RaiseAndSetIfChanged(ref _value, val, nameof(Value)); - RaiseAndSetIfChanged(ref _type, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(Type)); + RaiseAndSetIfChanged(ref _assignedType, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(AssignedType)); } } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs index fdbd8c1aa3..080eab072c 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs @@ -14,7 +14,7 @@ namespace Avalonia.Diagnostics.ViewModels public abstract object Key { get; } public abstract string Name { get; } public abstract string Group { get; } - public abstract string Type { get; } + public abstract string AssignedType { get; } public abstract string Value { get; set; } public abstract string Priority { get; } public abstract bool? IsAttached { get; } diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml index 4b37438993..22ad3374ed 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml @@ -33,7 +33,7 @@ - + From 4c3666ba214a9926d6468eb912ec4ea5e424b1d7 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 20 Jul 2021 16:18:36 +0200 Subject: [PATCH 002/305] feat(DevTools): Add PropertyType on ControlDettails --- .../ViewModels/AvaloniaPropertyViewModel.cs | 4 +++ .../ViewModels/ClrPropertyViewModel.cs | 4 +++ .../ViewModels/PropertyViewModel.cs | 26 ++++++++++++++++--- .../Diagnostics/Views/ControlDetailsView.xaml | 1 + 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs index 6bd26e39d6..68e12b545e 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs @@ -7,6 +7,7 @@ namespace Avalonia.Diagnostics.ViewModels private object? _value; private string _priority; private string _group; + private readonly string _propertyType; #nullable disable // Remove "nullable disable" after MemberNotNull will work on our CI. @@ -20,6 +21,7 @@ namespace Avalonia.Diagnostics.ViewModels $"[{property.OwnerType.Name}.{property.Name}]" : property.Name; + _propertyType = GetTypeName(property.PropertyType); Update(); } @@ -50,6 +52,8 @@ namespace Avalonia.Diagnostics.ViewModels public override string Group => _group; + public override string PropertyType => _propertyType; + // [MemberNotNull(nameof(_type), nameof(_group), nameof(_priority))] public override void Update() { diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs index b87d2b0b53..cbbf3e2fbb 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs @@ -7,6 +7,7 @@ namespace Avalonia.Diagnostics.ViewModels private readonly object _target; private string _assignedType; private object? _value; + private readonly string _propertyType; #nullable disable // Remove "nullable disable" after MemberNotNull will work on our CI. @@ -25,6 +26,8 @@ namespace Avalonia.Diagnostics.ViewModels Name = property.DeclaringType.Name + '.' + property.Name; } + _propertyType = GetTypeName(property.PropertyType); + Update(); } @@ -34,6 +37,7 @@ namespace Avalonia.Diagnostics.ViewModels public override string Group => "CLR Properties"; public override string AssignedType => _assignedType; + public override string PropertyType => _propertyType; public override string Value { diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs index 080eab072c..067693de38 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs @@ -2,6 +2,7 @@ using System.ComponentModel; using System.Globalization; using System.Reflection; +using System.Linq; namespace Avalonia.Diagnostics.ViewModels { @@ -17,8 +18,27 @@ namespace Avalonia.Diagnostics.ViewModels public abstract string AssignedType { get; } public abstract string Value { get; set; } public abstract string Priority { get; } - public abstract bool? IsAttached { get; } - public abstract void Update(); + public abstract bool? IsAttached { get; } + public abstract void Update(); + public abstract string PropertyType { get; } + + + protected static string GetTypeName(Type type) + { + var name = type.Name; + if (Nullable.GetUnderlyingType(type) is Type nullable) + { + name = nullable.Name + "?"; + } + else if (type.IsGenericType) + { + var definition = type.GetGenericTypeDefinition(); + var arguments = type.GetGenericArguments(); + name = definition.Name.Substring(0, definition.Name.IndexOf('`')); + name = $"{name}<{string.Join(",", arguments.Select(GetTypeName))}>"; + } + return name; + } protected static string ConvertToString(object? value) { @@ -30,7 +50,7 @@ namespace Avalonia.Diagnostics.ViewModels var converter = TypeDescriptor.GetConverter(value); //CollectionConverter does not deliver any important information. It just displays "(Collection)". - if (!converter.CanConvertTo(typeof(string)) || + if (!converter.CanConvertTo(typeof(string)) || converter.GetType() == typeof(CollectionConverter)) { return value.ToString() ?? "(null)"; diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml index 22ad3374ed..b92ea85227 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml @@ -34,6 +34,7 @@ + From 67f83633ce3e7615dd97707e38799c2b769451e5 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 20 Jul 2021 16:26:19 +0200 Subject: [PATCH 003/305] feat(DevTools): Allowed to decode Nullable and Generic Type for AssignedType --- .../Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs | 4 ++-- .../Diagnostics/ViewModels/ClrPropertyViewModel.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs index 68e12b545e..29e049a5d8 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/AvaloniaPropertyViewModel.cs @@ -60,7 +60,7 @@ namespace Avalonia.Diagnostics.ViewModels if (Property.IsDirect) { RaiseAndSetIfChanged(ref _value, _target.GetValue(Property), nameof(Value)); - RaiseAndSetIfChanged(ref _assignedType, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(AssignedType)); + RaiseAndSetIfChanged(ref _assignedType, GetTypeName(_value?.GetType() ?? Property.PropertyType), nameof(AssignedType)); RaiseAndSetIfChanged(ref _priority, "Direct", nameof(Priority)); _group = "Properties"; @@ -70,7 +70,7 @@ namespace Avalonia.Diagnostics.ViewModels var val = _target.GetDiagnostic(Property); RaiseAndSetIfChanged(ref _value, val?.Value, nameof(Value)); - RaiseAndSetIfChanged(ref _assignedType, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(AssignedType)); + RaiseAndSetIfChanged(ref _assignedType, GetTypeName(_value?.GetType() ?? Property.PropertyType), nameof(AssignedType)); if (val != null) { diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs index cbbf3e2fbb..fe48179150 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ClrPropertyViewModel.cs @@ -64,7 +64,7 @@ namespace Avalonia.Diagnostics.ViewModels { var val = Property.GetValue(_target); RaiseAndSetIfChanged(ref _value, val, nameof(Value)); - RaiseAndSetIfChanged(ref _assignedType, _value?.GetType().Name ?? Property.PropertyType.Name, nameof(AssignedType)); + RaiseAndSetIfChanged(ref _assignedType, GetTypeName(_value?.GetType() ?? Property.PropertyType), nameof(AssignedType)); } } } From 3efcd9d259c43d756d5c1ee1ad548d15cac171f2 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 20 Jul 2021 16:35:18 +0200 Subject: [PATCH 004/305] feat(DevTools): Allow caching of GetTypeName --- .../ViewModels/PropertyViewModel.cs | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs index 067693de38..1de1c34ea0 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs @@ -3,6 +3,7 @@ using System.ComponentModel; using System.Globalization; using System.Reflection; using System.Linq; +using System.Runtime.CompilerServices; namespace Avalonia.Diagnostics.ViewModels { @@ -11,6 +12,8 @@ namespace Avalonia.Diagnostics.ViewModels private const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static; private static readonly Type[] StringParameter = { typeof(string) }; private static readonly Type[] StringIFormatProviderParameters = { typeof(string), typeof(IFormatProvider) }; + private static readonly ConditionalWeakTable s_getTypeNameCache = + new ConditionalWeakTable(); public abstract object Key { get; } public abstract string Name { get; } @@ -25,17 +28,21 @@ namespace Avalonia.Diagnostics.ViewModels protected static string GetTypeName(Type type) { - var name = type.Name; - if (Nullable.GetUnderlyingType(type) is Type nullable) + if (!s_getTypeNameCache.TryGetValue(type, out var name)) { - name = nullable.Name + "?"; - } - else if (type.IsGenericType) - { - var definition = type.GetGenericTypeDefinition(); - var arguments = type.GetGenericArguments(); - name = definition.Name.Substring(0, definition.Name.IndexOf('`')); - name = $"{name}<{string.Join(",", arguments.Select(GetTypeName))}>"; + name = type.Name; + if (Nullable.GetUnderlyingType(type) is Type nullable) + { + name = nullable.Name + "?"; + } + else if (type.IsGenericType) + { + var definition = type.GetGenericTypeDefinition(); + var arguments = type.GetGenericArguments(); + name = definition.Name.Substring(0, definition.Name.IndexOf('`')); + name = $"{name}<{string.Join(",", arguments.Select(GetTypeName))}>"; + } + s_getTypeNameCache.Add(type, name); } return name; } From d0e810305192ab8d058095f759743bae06103628 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 21 Jul 2021 09:25:10 +0200 Subject: [PATCH 005/305] feat(DevTools): Allow toggle PropertyType column visibility --- .../Diagnostics/ViewModels/MainViewModel.cs | 16 ++++++++++++++-- .../Diagnostics/Views/ControlDetailsView.xaml | 5 ++++- .../Diagnostics/Views/MainView.xaml | 10 ++++++++++ 3 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs index 3f367165ac..90f127acd2 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs @@ -22,6 +22,7 @@ namespace Avalonia.Diagnostics.ViewModels private bool _shouldVisualizeMarginPadding = true; private bool _shouldVisualizeDirtyRects; private bool _showFpsOverlay; + private bool _showPropertyType; #nullable disable // Remove "nullable disable" after MemberNotNull will work on our CI. @@ -46,7 +47,7 @@ namespace Avalonia.Diagnostics.ViewModels get => _shouldVisualizeMarginPadding; set => RaiseAndSetIfChanged(ref _shouldVisualizeMarginPadding, value); } - + public bool ShouldVisualizeDirtyRects { get => _shouldVisualizeDirtyRects; @@ -151,7 +152,7 @@ namespace Avalonia.Diagnostics.ViewModels get { return _pointerOverElement; } private set { RaiseAndSetIfChanged(ref _pointerOverElement, value); } } - + private void UpdateConsoleContext(ConsoleContext context) { context.root = _root; @@ -220,5 +221,16 @@ namespace Avalonia.Diagnostics.ViewModels { StartupScreenIndex = options.StartupScreenIndex; } + + public bool ShowDettailsPropertyType + { + get => _showPropertyType; + private set => RaiseAndSetIfChanged(ref _showPropertyType , value); + } + + public void ToggleShowDettailsPropertyType(object paramter) + { + ShowDettailsPropertyType = !ShowDettailsPropertyType; + } } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml index b92ea85227..5dfc75106a 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml @@ -34,7 +34,10 @@ - + diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml index 8c4db33f91..6d01eb27a1 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml @@ -15,6 +15,16 @@ IsEnabled="False"/> + + + + + + + + From 739d9de5b7c70d2d35d28063e19663745919ffb4 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 1 Sep 2021 12:32:40 +0200 Subject: [PATCH 006/305] feat(DevTools): Shows the property type and the type assigned to the property in a single or split column. --- .../Diagnostics/ViewModels/PropertyViewModel.cs | 3 +++ .../Diagnostics/Views/ControlDetailsView.xaml | 9 ++++++++- src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs index 1de1c34ea0..d3cdff6e71 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/PropertyViewModel.cs @@ -24,6 +24,9 @@ namespace Avalonia.Diagnostics.ViewModels public abstract bool? IsAttached { get; } public abstract void Update(); public abstract string PropertyType { get; } + public string Type => PropertyType == AssignedType + ? PropertyType + : $"{PropertyType} {{{AssignedType}}}"; protected static string GetTypeName(Type type) diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml index 5dfc75106a..e6965884b1 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/ControlDetailsView.xaml @@ -33,7 +33,14 @@ - + + - + Date: Wed, 1 Sep 2021 17:03:26 +0200 Subject: [PATCH 007/305] feat: Added Post to IDispatcher --- src/Avalonia.Base/Threading/IDispatcher.cs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Threading/IDispatcher.cs b/src/Avalonia.Base/Threading/IDispatcher.cs index 8f46f99283..538fa028b9 100644 --- a/src/Avalonia.Base/Threading/IDispatcher.cs +++ b/src/Avalonia.Base/Threading/IDispatcher.cs @@ -27,6 +27,15 @@ namespace Avalonia.Threading /// A task that can be used to track the method's execution. void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal); + /// + /// Invokes a method on the dispatcher thread. + /// + /// type of argument + /// The method to call. + /// The argument of method to call. + /// The priority with which to invoke the method. + void Post(Action action, T arg, DispatcherPriority priority = DispatcherPriority.Normal); + /// /// Posts an action that will be invoked on the dispatcher thread. /// @@ -59,4 +68,4 @@ namespace Avalonia.Threading /// A task that represents a proxy for the task returned by . Task InvokeAsync(Func> function, DispatcherPriority priority = DispatcherPriority.Normal); } -} \ No newline at end of file +} From 75bd449a6901f2a405daeeebc79c9d92e4d68b8a Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 1 Sep 2021 17:18:44 +0200 Subject: [PATCH 008/305] feat: Implement Post method of IDispatcher. --- src/Avalonia.Base/ApiCompatBaseline.txt | 3 + src/Avalonia.Base/Threading/Dispatcher.cs | 11 ++- src/Avalonia.Base/Threading/JobRunner.cs | 84 ++++++++++++++++--- .../Avalonia.UnitTests/ImmediateDispatcher.cs | 6 ++ 4 files changed, 90 insertions(+), 14 deletions(-) create mode 100644 src/Avalonia.Base/ApiCompatBaseline.txt diff --git a/src/Avalonia.Base/ApiCompatBaseline.txt b/src/Avalonia.Base/ApiCompatBaseline.txt new file mode 100644 index 0000000000..4701a83175 --- /dev/null +++ b/src/Avalonia.Base/ApiCompatBaseline.txt @@ -0,0 +1,3 @@ +Compat issues with assembly Avalonia.Base: +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Threading.IDispatcher.Post(System.Action, T, Avalonia.Threading.DispatcherPriority)' is present in the implementation but not in the contract. +Total Issues: 1 diff --git a/src/Avalonia.Base/Threading/Dispatcher.cs b/src/Avalonia.Base/Threading/Dispatcher.cs index fe2cec11f0..217f1b9c3f 100644 --- a/src/Avalonia.Base/Threading/Dispatcher.cs +++ b/src/Avalonia.Base/Threading/Dispatcher.cs @@ -81,7 +81,7 @@ namespace Avalonia.Threading Contract.Requires(action != null); return _jobRunner.InvokeAsync(action, priority); } - + /// public Task InvokeAsync(Func function, DispatcherPriority priority = DispatcherPriority.Normal) { @@ -110,6 +110,13 @@ namespace Avalonia.Threading _jobRunner.Post(action, priority); } + /// + public void Post(Action action, T arg, DispatcherPriority priority = DispatcherPriority.Normal) + { + Contract.Requires(action != null); + _jobRunner.Post(action, arg, priority); + } + /// /// This is needed for platform backends that don't have internal priority system (e. g. win32) /// To ensure that there are no jobs with higher priority @@ -142,4 +149,4 @@ namespace Avalonia.Threading } } } -} \ No newline at end of file +} diff --git a/src/Avalonia.Base/Threading/JobRunner.cs b/src/Avalonia.Base/Threading/JobRunner.cs index 58f623fb3f..7aeb1972ea 100644 --- a/src/Avalonia.Base/Threading/JobRunner.cs +++ b/src/Avalonia.Base/Threading/JobRunner.cs @@ -13,7 +13,7 @@ namespace Avalonia.Threading { private IPlatformThreadingInterface _platform; - private readonly Queue[] _queues = Enumerable.Range(0, (int) DispatcherPriority.MaxValue + 1) + private readonly Queue[] _queues = Enumerable.Range(0, (int)DispatcherPriority.MaxValue + 1) .Select(_ => new Queue()).ToArray(); public JobRunner(IPlatformThreadingInterface platform) @@ -59,7 +59,7 @@ namespace Avalonia.Threading /// A task that can be used to track the method's execution. public Task InvokeAsync(Func function, DispatcherPriority priority) { - var job = new Job(function, priority); + var job = new JobWithResult(function, priority); AddJob(job); return job.Task; } @@ -75,6 +75,17 @@ namespace Avalonia.Threading AddJob(new Job(action, priority, true)); } + /// + /// Post action that will be invoked on main thread + /// + /// The method to call. + /// The parameter of method to call. + /// The priority with which to invoke the method. + internal void Post(Action action, T parameter, DispatcherPriority priority) + { + AddJob(new Job(action, parameter, priority, true)); + } + /// /// Allows unit tests to change the platform threading interface. /// @@ -86,7 +97,7 @@ namespace Avalonia.Threading private void AddJob(IJob job) { bool needWake; - var queue = _queues[(int) job.Priority]; + var queue = _queues[(int)job.Priority]; lock (queue) { needWake = queue.Count == 0; @@ -98,7 +109,7 @@ namespace Avalonia.Threading private IJob GetNextJob(DispatcherPriority minimumPriority) { - for (int c = (int) DispatcherPriority.MaxValue; c >= (int) minimumPriority; c--) + for (int c = (int)DispatcherPriority.MaxValue; c >= (int)minimumPriority; c--) { var q = _queues[c]; lock (q) @@ -109,14 +120,14 @@ namespace Avalonia.Threading } return null; } - + private interface IJob { /// /// Gets the job priority. /// DispatcherPriority Priority { get; } - + /// /// Runs the job. /// @@ -157,7 +168,7 @@ namespace Avalonia.Threading /// The task. /// public Task Task => _taskCompletionSource?.Task; - + /// void IJob.Run() { @@ -177,11 +188,60 @@ namespace Avalonia.Threading } } } - + /// - /// A job to run. + /// A tipizzed job to run. /// - private sealed class Job : IJob + private sealed class Job : IJob + { + private readonly Action _action; + private readonly T _parameter; + private readonly TaskCompletionSource _taskCompletionSource; + + /// + /// Initializes a new instance of the class. + /// + /// The method to call. + /// The parameter of method to call. + /// The job priority. + /// Do not wrap exception in TaskCompletionSource + + public Job(Action action, T parameter, DispatcherPriority priority, bool throwOnUiThread) + { + _action = action; + _parameter = parameter; + Priority = priority; + _taskCompletionSource = throwOnUiThread ? null : new TaskCompletionSource(); + } + + /// + public DispatcherPriority Priority { get; } + + /// + void IJob.Run() + { + if (_taskCompletionSource == null) + { + _action(_parameter); + return; + } + try + { + _action(_parameter); + _taskCompletionSource.SetResult(null); + } + catch (Exception e) + { + _taskCompletionSource.SetException(e); + } + } + } + + + /// + /// A job to run thath return value. + /// + private sealed class JobWithResult : IJob { private readonly Func _function; private readonly TaskCompletionSource _taskCompletionSource; @@ -191,7 +251,7 @@ namespace Avalonia.Threading /// /// The method to call. /// The job priority. - public Job(Func function, DispatcherPriority priority) + public JobWithResult(Func function, DispatcherPriority priority) { _function = function; Priority = priority; @@ -200,7 +260,7 @@ namespace Avalonia.Threading /// public DispatcherPriority Priority { get; } - + /// /// The task. /// diff --git a/tests/Avalonia.UnitTests/ImmediateDispatcher.cs b/tests/Avalonia.UnitTests/ImmediateDispatcher.cs index fac4ee64e7..5f0d41590f 100644 --- a/tests/Avalonia.UnitTests/ImmediateDispatcher.cs +++ b/tests/Avalonia.UnitTests/ImmediateDispatcher.cs @@ -21,6 +21,12 @@ namespace Avalonia.UnitTests action(); } + /// + public void Post(Action action, T arg, DispatcherPriority priority = DispatcherPriority.Normal) + { + action(arg); + } + /// public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal) { From aa5df186f049065a7d2167a54f1d3725a8b23738 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Thu, 2 Sep 2021 09:40:54 +0200 Subject: [PATCH 009/305] fixes: XML Code Comment --- src/Avalonia.Base/Threading/JobRunner.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Base/Threading/JobRunner.cs b/src/Avalonia.Base/Threading/JobRunner.cs index 7aeb1972ea..357fbd9b59 100644 --- a/src/Avalonia.Base/Threading/JobRunner.cs +++ b/src/Avalonia.Base/Threading/JobRunner.cs @@ -190,8 +190,9 @@ namespace Avalonia.Threading } /// - /// A tipizzed job to run. + /// A typed job to run. /// + /// Type of job parameter private sealed class Job : IJob { private readonly Action _action; @@ -237,10 +238,10 @@ namespace Avalonia.Threading } } - /// /// A job to run thath return value. /// + /// Type of job result private sealed class JobWithResult : IJob { private readonly Func _function; From 82729a1bd92d35a2f7c4688c1a508024abbd9027 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Mon, 18 Oct 2021 14:57:58 +0200 Subject: [PATCH 010/305] fixes: some null annotation --- src/Avalonia.Base/Data/BindingValue.cs | 2 ++ .../Data/Converters/MethodToCommandConverter.cs | 2 +- src/Avalonia.Controls/Application.cs | 2 +- src/Avalonia.Controls/Primitives/Popup.cs | 8 ++++---- src/Avalonia.Controls/SplitView.cs | 10 +++++----- src/Avalonia.Input/ICommandSource.cs | 6 +++--- src/Avalonia.Styling/Styling/Setter.cs | 8 ++++++++ src/tools/MicroComGenerator/CSharpGen.Utils.cs | 2 +- 8 files changed, 25 insertions(+), 15 deletions(-) diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs index 93948e54ee..414baf88fc 100644 --- a/src/Avalonia.Base/Data/BindingValue.cs +++ b/src/Avalonia.Base/Data/BindingValue.cs @@ -247,7 +247,9 @@ namespace Avalonia.Data UnsetValueType _ => Unset, DoNothingType _ => DoNothing, BindingNotification n => n.ToBindingValue().Cast(), +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. _ => new BindingValue((T)value) +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. }; } diff --git a/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs b/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs index 7ff0a8ceca..add2280567 100644 --- a/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs +++ b/src/Avalonia.Base/Data/Converters/MethodToCommandConverter.cs @@ -170,7 +170,7 @@ namespace Avalonia.Data.Converters .Compile(); } - private static Expression? ConvertTarget(object? target, MethodInfo method) => + private static Expression ConvertTarget(object target, MethodInfo method) => target is null ? null : Expression.Convert(Expression.Constant(target), method.DeclaringType); internal class WeakPropertyChangedProxy diff --git a/src/Avalonia.Controls/Application.cs b/src/Avalonia.Controls/Application.cs index 157bebe02b..bd53ec0100 100644 --- a/src/Avalonia.Controls/Application.cs +++ b/src/Avalonia.Controls/Application.cs @@ -175,7 +175,7 @@ namespace Avalonia /// - /// - /// - public IApplicationLifetime ApplicationLifetime { get; set; } + public IApplicationLifetime? ApplicationLifetime { get; set; } event Action> IGlobalStyles.GlobalStylesAdded { diff --git a/src/Avalonia.Controls/Primitives/Popup.cs b/src/Avalonia.Controls/Primitives/Popup.cs index 856bcd1079..50f130ab71 100644 --- a/src/Avalonia.Controls/Primitives/Popup.cs +++ b/src/Avalonia.Controls/Primitives/Popup.cs @@ -91,8 +91,8 @@ namespace Avalonia.Controls.Primitives public static readonly StyledProperty OverlayDismissEventPassThroughProperty = AvaloniaProperty.Register(nameof(OverlayDismissEventPassThrough)); - public static readonly DirectProperty OverlayInputPassThroughElementProperty = - AvaloniaProperty.RegisterDirect( + public static readonly DirectProperty OverlayInputPassThroughElementProperty = + AvaloniaProperty.RegisterDirect( nameof(OverlayInputPassThroughElement), o => o.OverlayInputPassThroughElement, (o, v) => o.OverlayInputPassThroughElement = v); @@ -136,7 +136,7 @@ namespace Avalonia.Controls.Primitives private bool _isOpen; private bool _ignoreIsOpenChanged; private PopupOpenState? _openState; - private IInputElement _overlayInputPassThroughElement; + private IInputElement? _overlayInputPassThroughElement; private Action? _popupHostChangedHandler; /// @@ -308,7 +308,7 @@ namespace Avalonia.Controls.Primitives /// Gets or sets an element that should receive pointer input events even when underneath /// the popup's overlay. /// - public IInputElement OverlayInputPassThroughElement + public IInputElement? OverlayInputPassThroughElement { get => _overlayInputPassThroughElement; set => SetAndRaise(OverlayInputPassThroughElementProperty, ref _overlayInputPassThroughElement, value); diff --git a/src/Avalonia.Controls/SplitView.cs b/src/Avalonia.Controls/SplitView.cs index 0e35c610b2..6a0d4e2023 100644 --- a/src/Avalonia.Controls/SplitView.cs +++ b/src/Avalonia.Controls/SplitView.cs @@ -129,14 +129,14 @@ namespace Avalonia.Controls /// /// Defines the property /// - public static readonly StyledProperty PaneProperty = - AvaloniaProperty.Register(nameof(Pane)); + public static readonly StyledProperty PaneProperty = + AvaloniaProperty.Register(nameof(Pane)); /// /// Defines the property. /// - public static readonly StyledProperty PaneTemplateProperty = - AvaloniaProperty.Register(nameof(PaneTemplate)); + public static readonly StyledProperty PaneTemplateProperty = + AvaloniaProperty.Register(nameof(PaneTemplate)); /// /// Defines the property @@ -267,7 +267,7 @@ namespace Avalonia.Controls /// /// Gets or sets the data template used to display the header content of the control. /// - public IDataTemplate? PaneTemplate + public IDataTemplate PaneTemplate { get => GetValue(PaneTemplateProperty); set => SetValue(PaneTemplateProperty, value); diff --git a/src/Avalonia.Input/ICommandSource.cs b/src/Avalonia.Input/ICommandSource.cs index eed71759d5..410b3a2e47 100644 --- a/src/Avalonia.Input/ICommandSource.cs +++ b/src/Avalonia.Input/ICommandSource.cs @@ -1,5 +1,5 @@ using System.Windows.Input; - +#nullable enable namespace Avalonia.Input { /// @@ -12,13 +12,13 @@ namespace Avalonia.Input /// Classes that implement this interface should enable or disable based on the command's CanExecute return value. /// The property may be implemented as read-write if desired. /// - ICommand Command { get; } + ICommand? Command { get; } /// /// The parameter that will be passed to the command when executing the command. /// The property may be implemented as read-write if desired. /// - object CommandParameter { get; } + object? CommandParameter { get; } /// diff --git a/src/Avalonia.Styling/Styling/Setter.cs b/src/Avalonia.Styling/Styling/Setter.cs index 1f3d6335a9..9e8969c164 100644 --- a/src/Avalonia.Styling/Styling/Setter.cs +++ b/src/Avalonia.Styling/Styling/Setter.cs @@ -101,7 +101,11 @@ namespace Avalonia.Styling data.result = new PropertySetterInstance( data.target, property, +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8604 // Possible null reference argument. (T)data.value); +#pragma warning restore CS8604 // Possible null reference argument. +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. } } @@ -128,7 +132,11 @@ namespace Avalonia.Styling data.result = new PropertySetterInstance( data.target, property, +#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. +#pragma warning disable CS8604 // Possible null reference argument. (T)data.value); +#pragma warning restore CS8604 // Possible null reference argument. +#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. } } diff --git a/src/tools/MicroComGenerator/CSharpGen.Utils.cs b/src/tools/MicroComGenerator/CSharpGen.Utils.cs index da845b0ecd..28baaa65f8 100644 --- a/src/tools/MicroComGenerator/CSharpGen.Utils.cs +++ b/src/tools/MicroComGenerator/CSharpGen.Utils.cs @@ -40,7 +40,7 @@ namespace MicroComGenerator SyntaxToken Semicolon() => Token(SyntaxKind.SemicolonToken); static VariableDeclarationSyntax DeclareVar(string type, string name, - ExpressionSyntax? initializer = null) + ExpressionSyntax initializer = null) => VariableDeclaration(ParseTypeName(type), SingletonSeparatedList(VariableDeclarator(name) .WithInitializer(initializer == null ? null : EqualsValueClause(initializer)))); From 0309dda390b0583b07d1298c6c256ebd06b3f473 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 19 Oct 2021 10:02:54 +0200 Subject: [PATCH 011/305] fixes: Replace CS8600 warning suppression with null-forgiving operator --- src/Avalonia.Base/Data/BindingValue.cs | 4 +--- src/Avalonia.Styling/Styling/Setter.cs | 12 ++---------- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs index 414baf88fc..0e7bdfe0bf 100644 --- a/src/Avalonia.Base/Data/BindingValue.cs +++ b/src/Avalonia.Base/Data/BindingValue.cs @@ -247,9 +247,7 @@ namespace Avalonia.Data UnsetValueType _ => Unset, DoNothingType _ => DoNothing, BindingNotification n => n.ToBindingValue().Cast(), -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. - _ => new BindingValue((T)value) -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. + _ => new BindingValue((T)value!) }; } diff --git a/src/Avalonia.Styling/Styling/Setter.cs b/src/Avalonia.Styling/Styling/Setter.cs index 9e8969c164..168a882499 100644 --- a/src/Avalonia.Styling/Styling/Setter.cs +++ b/src/Avalonia.Styling/Styling/Setter.cs @@ -101,11 +101,7 @@ namespace Avalonia.Styling data.result = new PropertySetterInstance( data.target, property, -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. -#pragma warning disable CS8604 // Possible null reference argument. - (T)data.value); -#pragma warning restore CS8604 // Possible null reference argument. -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. + (T)data.value!); } } @@ -132,11 +128,7 @@ namespace Avalonia.Styling data.result = new PropertySetterInstance( data.target, property, -#pragma warning disable CS8600 // Converting null literal or possible null value to non-nullable type. -#pragma warning disable CS8604 // Possible null reference argument. - (T)data.value); -#pragma warning restore CS8604 // Possible null reference argument. -#pragma warning restore CS8600 // Converting null literal or possible null value to non-nullable type. + (T)data.value!); } } From a828e5b4f5664a4aaf50280a7cf423d59e248da7 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 19 Oct 2021 10:12:36 +0200 Subject: [PATCH 012/305] fixes: MenuFlyout Possible null reference argument for parameter --- src/Avalonia.Controls/Flyouts/FlyoutBase.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs index 4b903d056c..b874d149bf 100644 --- a/src/Avalonia.Controls/Flyouts/FlyoutBase.cs +++ b/src/Avalonia.Controls/Flyouts/FlyoutBase.cs @@ -562,8 +562,12 @@ namespace Avalonia.Controls.Primitives return eventArgs.Cancel; } - internal static void SetPresenterClasses(IControl presenter, Classes classes) + internal static void SetPresenterClasses(IControl? presenter, Classes classes) { + if(presenter is null) + { + return; + } //Remove any classes no longer in use, ignoring pseudo classes for (int i = presenter.Classes.Count - 1; i >= 0; i--) { From 895fd718d9f88a68b258cff12a545f642549f63c Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 19 Oct 2021 10:42:03 +0200 Subject: [PATCH 013/305] fixes: ConstantValueEntry Possible null reference argument for parameter --- src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs index dc4a1d88c1..ebcd064626 100644 --- a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs @@ -30,7 +30,7 @@ namespace Avalonia.PropertyStore IValueSink sink) { Property = property; - _value = value; + _value = value!; Priority = priority; _sink = sink; } From 22644028ca5c52843f87f45f42a2a44ed2eab7fe Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Tue, 19 Oct 2021 10:44:22 +0200 Subject: [PATCH 014/305] fixes: ValueStore Possible null reference argument for parameter --- src/Avalonia.Base/ValueStore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs index 495f13e1a9..151e5d1949 100644 --- a/src/Avalonia.Base/ValueStore.cs +++ b/src/Avalonia.Base/ValueStore.cs @@ -192,7 +192,7 @@ namespace Avalonia _values.SetValue(property, sentinel); } - NotifyValueChanged(property, old, default, BindingPriority.Unset); + NotifyValueChanged(property, old!, default!, BindingPriority.Unset); } } } From 7c414bb3b10fc6199f280fff8be02854724504f8 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Wed, 20 Oct 2021 11:14:33 +0200 Subject: [PATCH 015/305] feat(DevTools): Allow to Show/Hide implemented interfaces on Control Details --- .../Diagnostics/DevToolsOptions.cs | 5 ++ .../ViewModels/ControlDetailsViewModel.cs | 46 +++++++++++-------- .../Diagnostics/ViewModels/MainViewModel.cs | 21 ++++++++- .../ViewModels/TreePageViewModel.cs | 6 +++ .../Diagnostics/Views/MainView.xaml | 10 ++++ 5 files changed, 67 insertions(+), 21 deletions(-) diff --git a/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs b/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs index 5336dca65b..6b5e7b1ec1 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/DevToolsOptions.cs @@ -27,5 +27,10 @@ namespace Avalonia.Diagnostics /// Get or set the startup screen index where the DevTools window will be displayed. /// public int? StartupScreenIndex { get; set; } + + /// + /// Gets or sets a value indicating whether DevTools should be displayed implemented interfaces on Control details. The default value is true. + /// + public bool ShowImplementedInterfaces { get; set; } = true; } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs index 3790951b0c..45e578dc10 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/ControlDetailsViewModel.cs @@ -17,11 +17,12 @@ namespace Avalonia.Diagnostics.ViewModels internal class ControlDetailsViewModel : ViewModelBase, IDisposable { private readonly IVisual _control; - private readonly IDictionary> _propertyIndex; + private IDictionary>? _propertyIndex; private PropertyViewModel? _selectedProperty; private bool _snapshotStyles; private bool _showInactiveStyles; private string? _styleStatus; + private DataGridCollectionView _propertiesView; public ControlDetailsViewModel(TreePageViewModel treePage, IVisual control) { @@ -29,19 +30,6 @@ namespace Avalonia.Diagnostics.ViewModels TreePage = treePage; - var properties = GetAvaloniaProperties(control) - .Concat(GetClrProperties(control)) - .OrderBy(x => x, PropertyComparer.Instance) - .ThenBy(x => x.Name) - .ToList(); - - _propertyIndex = properties.GroupBy(x => x.Key).ToDictionary(x => x.Key, x => x.ToList()); - - var view = new DataGridCollectionView(properties); - view.GroupDescriptions.Add(new DataGridPathGroupDescription(nameof(AvaloniaPropertyViewModel.Group))); - view.Filter = FilterProperty; - PropertiesView = view; - Layout = new ControlLayoutViewModel(control); if (control is INotifyPropertyChanged inpc) @@ -133,7 +121,7 @@ namespace Avalonia.Diagnostics.ViewModels public TreePageViewModel TreePage { get; } - public DataGridCollectionView PropertiesView { get; } + public DataGridCollectionView PropertiesView { get => _propertiesView; private set => RaiseAndSetIfChanged( ref _propertiesView , value); } public ObservableCollection AppliedStyles { get; } @@ -227,18 +215,21 @@ namespace Avalonia.Diagnostics.ViewModels } } - private IEnumerable GetClrProperties(object o) + private IEnumerable GetClrProperties(object o, bool showImplementedInterfaces) { foreach (var p in GetClrProperties(o, o.GetType())) { yield return p; } - foreach (var i in o.GetType().GetInterfaces()) + if (showImplementedInterfaces) { - foreach (var p in GetClrProperties(o, i)) + foreach (var i in o.GetType().GetInterfaces()) { - yield return p; + foreach (var p in GetClrProperties(o, i)) + { + yield return p; + } } } } @@ -378,5 +369,22 @@ namespace Avalonia.Diagnostics.ViewModels } } } + + public void UpdatePropertiesView(bool showImplementedInterfaces) + { + + var properties = GetAvaloniaProperties(_control) + .Concat(GetClrProperties(_control, showImplementedInterfaces)) + .OrderBy(x => x, PropertyComparer.Instance) + .ThenBy(x => x.Name) + .ToList(); + + _propertyIndex = properties.GroupBy(x => x.Key).ToDictionary(x => x.Key, x => x.ToList()); + + var view = new DataGridCollectionView(properties); + view.GroupDescriptions.Add(new DataGridPathGroupDescription(nameof(AvaloniaPropertyViewModel.Group))); + view.Filter = FilterProperty; + PropertiesView = view; + } } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs index d0a4ad38c5..bb94ba16bb 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs @@ -22,6 +22,7 @@ namespace Avalonia.Diagnostics.ViewModels private bool _shouldVisualizeDirtyRects; private bool _showFpsOverlay; private bool _freezePopups; + private bool _showImplementedInterfaces; #nullable disable // Remove "nullable disable" after MemberNotNull will work on our CI. @@ -52,7 +53,7 @@ namespace Avalonia.Diagnostics.ViewModels get => _shouldVisualizeMarginPadding; set => RaiseAndSetIfChanged(ref _shouldVisualizeMarginPadding, value); } - + public bool ShouldVisualizeDirtyRects { get => _shouldVisualizeDirtyRects; @@ -157,7 +158,7 @@ namespace Avalonia.Diagnostics.ViewModels get { return _pointerOverElement; } private set { RaiseAndSetIfChanged(ref _pointerOverElement, value); } } - + private void UpdateConsoleContext(ConsoleContext context) { context.root = _root; @@ -225,6 +226,22 @@ namespace Avalonia.Diagnostics.ViewModels public void SetOptions(DevToolsOptions options) { StartupScreenIndex = options.StartupScreenIndex; + ShowImplementedInterfaces = options.ShowImplementedInterfaces; + } + + public bool ShowImplementedInterfaces + { + get => _showImplementedInterfaces; + private set => RaiseAndSetIfChanged(ref _showImplementedInterfaces , value); + } + + public void ToggleShowImplementedInterfaces(object parametr) + { + ShowImplementedInterfaces = !ShowImplementedInterfaces; + if (Content is TreePageViewModel viewModel) + { + viewModel.UpdatePropertiesView(); + } } } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs index 4b18cf414a..f43896f810 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs +++ b/src/Avalonia.Diagnostics/Diagnostics/ViewModels/TreePageViewModel.cs @@ -39,6 +39,7 @@ namespace Avalonia.Diagnostics.ViewModels Details = value != null ? new ControlDetailsViewModel(this, value.Visual) : null; + Details?.UpdatePropertiesView(MainView.ShowImplementedInterfaces); Details?.UpdateStyleFilters(); } } @@ -134,5 +135,10 @@ namespace Avalonia.Diagnostics.ViewModels return null; } + + internal void UpdatePropertiesView() + { + Details?.UpdatePropertiesView(MainView?.ShowImplementedInterfaces ?? true); + } } } diff --git a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml index 6f2ac96a66..f45a65dbf3 100644 --- a/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml +++ b/src/Avalonia.Diagnostics/Diagnostics/Views/MainView.xaml @@ -38,6 +38,16 @@ IsEnabled="False" /> + + + + + + + + From 97a920db72a16a89aae24e2cb4d20b53a77d2883 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Sat, 23 Oct 2021 11:45:07 +0200 Subject: [PATCH 016/305] Review suggestions apply --- src/Avalonia.Base/Data/BindingValue.cs | 2 +- src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs | 2 +- src/Avalonia.Base/ValueStore.cs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs index 0e7bdfe0bf..e8c84ffb21 100644 --- a/src/Avalonia.Base/Data/BindingValue.cs +++ b/src/Avalonia.Base/Data/BindingValue.cs @@ -247,7 +247,7 @@ namespace Avalonia.Data UnsetValueType _ => Unset, DoNothingType _ => DoNothing, BindingNotification n => n.ToBindingValue().Cast(), - _ => new BindingValue((T)value!) + _ => new BindingValue((T?)value) }; } diff --git a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs index ebcd064626..dc4a1d88c1 100644 --- a/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs +++ b/src/Avalonia.Base/PropertyStore/ConstantValueEntry.cs @@ -30,7 +30,7 @@ namespace Avalonia.PropertyStore IValueSink sink) { Property = property; - _value = value!; + _value = value; Priority = priority; _sink = sink; } diff --git a/src/Avalonia.Base/ValueStore.cs b/src/Avalonia.Base/ValueStore.cs index 151e5d1949..495f13e1a9 100644 --- a/src/Avalonia.Base/ValueStore.cs +++ b/src/Avalonia.Base/ValueStore.cs @@ -192,7 +192,7 @@ namespace Avalonia _values.SetValue(property, sentinel); } - NotifyValueChanged(property, old!, default!, BindingPriority.Unset); + NotifyValueChanged(property, old, default, BindingPriority.Unset); } } } From 44225c66146cdfb63623052a19cc87f3639b29df Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Sat, 23 Oct 2021 12:31:46 +0200 Subject: [PATCH 017/305] fixes: Revert the fix, because the fix throw error CS8627 on Linux and macOS --- src/Avalonia.Base/Data/BindingValue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs index e8c84ffb21..93948e54ee 100644 --- a/src/Avalonia.Base/Data/BindingValue.cs +++ b/src/Avalonia.Base/Data/BindingValue.cs @@ -247,7 +247,7 @@ namespace Avalonia.Data UnsetValueType _ => Unset, DoNothingType _ => DoNothing, BindingNotification n => n.ToBindingValue().Cast(), - _ => new BindingValue((T?)value) + _ => new BindingValue((T)value) }; } From 67e5962680c831fa6046ded59c66125cef3675e7 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Thu, 28 Oct 2021 10:13:44 +0200 Subject: [PATCH 018/305] fix(TrayIcon): CommandParameter alow null --- src/Avalonia.Controls/TrayIcon.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/TrayIcon.cs b/src/Avalonia.Controls/TrayIcon.cs index 59edb6278a..9fbc2fc8b2 100644 --- a/src/Avalonia.Controls/TrayIcon.cs +++ b/src/Avalonia.Controls/TrayIcon.cs @@ -140,7 +140,7 @@ namespace Avalonia.Controls /// Gets or sets the parameter to pass to the property of a /// . /// - public object CommandParameter + public object? CommandParameter { get { return GetValue(CommandParameterProperty); } set { SetValue(CommandParameterProperty, value); } From 94eeb7d97c33779f5f79985ab81675940993153e Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Thu, 28 Oct 2021 10:14:07 +0200 Subject: [PATCH 019/305] restore fix --- src/Avalonia.Base/Data/BindingValue.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Base/Data/BindingValue.cs b/src/Avalonia.Base/Data/BindingValue.cs index 93948e54ee..e8c84ffb21 100644 --- a/src/Avalonia.Base/Data/BindingValue.cs +++ b/src/Avalonia.Base/Data/BindingValue.cs @@ -247,7 +247,7 @@ namespace Avalonia.Data UnsetValueType _ => Unset, DoNothingType _ => DoNothing, BindingNotification n => n.ToBindingValue().Cast(), - _ => new BindingValue((T)value) + _ => new BindingValue((T?)value) }; } From 59f4adcdd39ed878d9b8cf38936afd0d0cf2eb04 Mon Sep 17 00:00:00 2001 From: Giuseppe Lippolis Date: Sat, 23 Oct 2021 12:14:38 +0200 Subject: [PATCH 020/305] fix: Warning CS0067 The event is never used --- .../Platform/InternalPlatformThreadingInterface.cs | 2 ++ src/Avalonia.Controls/TextBoxTextInputMethodClient.cs | 2 +- src/Avalonia.DesignerSupport/Remote/FileWatcherTransport.cs | 2 +- src/Avalonia.FreeDesktop/DBusMenuExporter.cs | 6 +++--- src/Avalonia.Native/AvaloniaNativeMenuExporter.cs | 2 +- src/Avalonia.X11/X11Window.Xim.cs | 4 ++-- tests/Avalonia.Controls.UnitTests/ItemsSourceViewTests.cs | 2 +- 7 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs b/src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs index a5495fdfc9..6a95c2e047 100644 --- a/src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs +++ b/src/Avalonia.Controls/Platform/InternalPlatformThreadingInterface.cs @@ -85,7 +85,9 @@ namespace Avalonia.Controls.Platform public bool CurrentThreadIsLoopThread => TlsCurrentThreadIsLoopThread; public event Action Signaled; +#pragma warning disable CS0067 public event Action Tick; +#pragma warning restore CS0067 } } diff --git a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs index e8122dd311..c5a729afae 100644 --- a/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs +++ b/src/Avalonia.Controls/TextBoxTextInputMethodClient.cs @@ -18,7 +18,7 @@ namespace Avalonia.Controls public bool SupportsSurroundingText => false; public TextInputMethodSurroundingText SurroundingText => throw new NotSupportedException(); - public event EventHandler SurroundingTextChanged; + public event EventHandler SurroundingTextChanged { add { } remove { } } public string TextBeforeCursor => null; public string TextAfterCursor => null; diff --git a/src/Avalonia.DesignerSupport/Remote/FileWatcherTransport.cs b/src/Avalonia.DesignerSupport/Remote/FileWatcherTransport.cs index 0448a5c05d..45a6c97954 100644 --- a/src/Avalonia.DesignerSupport/Remote/FileWatcherTransport.cs +++ b/src/Avalonia.DesignerSupport/Remote/FileWatcherTransport.cs @@ -59,7 +59,7 @@ namespace Avalonia.DesignerSupport.Remote remove { _onMessage -= value; } } - public event Action OnException; + public event Action OnException { add { } remove { } } public void Start() { UpdaterThread(); diff --git a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs index 9e426688d8..206c24ad5e 100644 --- a/src/Avalonia.FreeDesktop/DBusMenuExporter.cs +++ b/src/Avalonia.FreeDesktop/DBusMenuExporter.cs @@ -413,10 +413,10 @@ namespace Avalonia.FreeDesktop #region Events private event Action<((int, IDictionary)[] updatedProps, (int, string[])[] removedProps)> - ItemsPropertiesUpdated; + ItemsPropertiesUpdated { add { } remove { } } private event Action<(uint revision, int parent)> LayoutUpdated; - private event Action<(int id, uint timestamp)> ItemActivationRequested; - private event Action PropertiesChanged; + private event Action<(int id, uint timestamp)> ItemActivationRequested { add { } remove { } } + private event Action PropertiesChanged { add { } remove { } } async Task IDBusMenu.WatchItemsPropertiesUpdatedAsync(Action<((int, IDictionary)[] updatedProps, (int, string[])[] removedProps)> handler, Action onError) { diff --git a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs index 4431e108ed..1582f794ae 100644 --- a/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs +++ b/src/Avalonia.Native/AvaloniaNativeMenuExporter.cs @@ -44,7 +44,7 @@ namespace Avalonia.Native public bool IsNativeMenuExported => _exported; - public event EventHandler OnIsNativeMenuExportedChanged; + public event EventHandler OnIsNativeMenuExportedChanged { add { } remove { } } public void SetNativeMenu(NativeMenu menu) { diff --git a/src/Avalonia.X11/X11Window.Xim.cs b/src/Avalonia.X11/X11Window.Xim.cs index 444c82fd22..ecb23ff097 100644 --- a/src/Avalonia.X11/X11Window.Xim.cs +++ b/src/Avalonia.X11/X11Window.Xim.cs @@ -112,8 +112,8 @@ namespace Avalonia.X11 public ValueTask HandleEventAsync(RawKeyEventArgs args, int keyVal, int keyCode) => new ValueTask(false); - public event Action Commit; - public event Action ForwardKey; + public event Action Commit { add { } remove { } } + public event Action ForwardKey { add { } remove { } } } diff --git a/tests/Avalonia.Controls.UnitTests/ItemsSourceViewTests.cs b/tests/Avalonia.Controls.UnitTests/ItemsSourceViewTests.cs index 529b3b1aa8..22a9b28648 100644 --- a/tests/Avalonia.Controls.UnitTests/ItemsSourceViewTests.cs +++ b/tests/Avalonia.Controls.UnitTests/ItemsSourceViewTests.cs @@ -47,7 +47,7 @@ namespace Avalonia.Controls.UnitTests private class InvalidCollection : INotifyCollectionChanged, IEnumerable { - public event NotifyCollectionChangedEventHandler CollectionChanged; + public event NotifyCollectionChangedEventHandler CollectionChanged { add { } remove { } } public IEnumerator GetEnumerator() { From 1a8cb9bba916fe3df8eb50b320b0a19b0a0fea90 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 28 Oct 2021 13:22:41 +0100 Subject: [PATCH 021/305] allow window to clear focus manager when it closes, preventing memory leak. --- src/Avalonia.Controls/WindowBase.cs | 6 ++++++ src/Avalonia.Input/ApiCompatBaseline.txt | 3 ++- src/Avalonia.Input/FocusManager.cs | 18 +++++++++++++++++- src/Avalonia.Input/IFocusManager.cs | 8 ++++++++ 4 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/Avalonia.Controls/WindowBase.cs b/src/Avalonia.Controls/WindowBase.cs index ee008efb04..5861d0452d 100644 --- a/src/Avalonia.Controls/WindowBase.cs +++ b/src/Avalonia.Controls/WindowBase.cs @@ -193,6 +193,12 @@ namespace Avalonia.Controls try { IsVisible = false; + + if (this is IFocusScope scope) + { + FocusManager.Instance?.RemoveFocusScope(scope); + } + base.HandleClosed(); } finally diff --git a/src/Avalonia.Input/ApiCompatBaseline.txt b/src/Avalonia.Input/ApiCompatBaseline.txt index 98eb8598d8..221ef63476 100644 --- a/src/Avalonia.Input/ApiCompatBaseline.txt +++ b/src/Avalonia.Input/ApiCompatBaseline.txt @@ -3,6 +3,7 @@ MembersMustExist : Member 'public Avalonia.Platform.IPlatformHandle Avalonia.Inp MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.Gestures.DoubleTappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.Gestures.RightTappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.Gestures.TappedEvent' does not exist in the implementation but it does exist in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.IFocusManager.ClearFocusScope(Avalonia.Input.IFocusScope)' is present in the implementation but not in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.InputElement.DoubleTappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.InputElement.TappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_DoubleTapped(System.EventHandler)' does not exist in the implementation but it does exist in the contract. @@ -10,4 +11,4 @@ MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_Tapped(Sy MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_DoubleTapped(System.EventHandler)' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Input.InputElement.remove_Tapped(System.EventHandler)' does not exist in the implementation but it does exist in the contract. TypesMustExist : Type 'Avalonia.Platform.IStandardCursorFactory' does not exist in the implementation but it does exist in the contract. -Total Issues: 11 +Total Issues: 12 diff --git a/src/Avalonia.Input/FocusManager.cs b/src/Avalonia.Input/FocusManager.cs index 1432092ba1..3e1ec84c03 100644 --- a/src/Avalonia.Input/FocusManager.cs +++ b/src/Avalonia.Input/FocusManager.cs @@ -145,7 +145,7 @@ namespace Avalonia.Input /// Notifies the focus manager of a change in focus scope. /// /// The new focus scope. - public void SetFocusScope(IFocusScope scope) + public void SetFocusScope(IFocusScope? scope) { scope = scope ?? throw new ArgumentNullException(nameof(scope)); @@ -162,6 +162,22 @@ namespace Avalonia.Input Focus(e); } + public void RemoveFocusScope(IFocusScope scope) + { + scope = scope ?? throw new ArgumentNullException(nameof(scope)); + + if (_focusScopes.TryGetValue(scope, out var e)) + { + SetFocusedElement(scope, null); + _focusScopes.Remove(scope); + } + + if (Scope == scope) + { + Scope = null; + } + } + public static bool GetIsFocusScope(IInputElement e) => e is IFocusScope; /// diff --git a/src/Avalonia.Input/IFocusManager.cs b/src/Avalonia.Input/IFocusManager.cs index e1b5087c3d..2510479a8e 100644 --- a/src/Avalonia.Input/IFocusManager.cs +++ b/src/Avalonia.Input/IFocusManager.cs @@ -35,5 +35,13 @@ namespace Avalonia.Input /// when it activates, e.g. when a Window is activated. /// void SetFocusScope(IFocusScope scope); + + /// + /// Notifies the focus manager that a focus scope has been removed. + /// + /// The focus scope to be removed. + /// This should not be called by client code. It is called by an + /// when it deactivates or closes, e.g. when a Window is closed. + void RemoveFocusScope(IFocusScope scope); } } From eb9f3343bf57346ecd5a599e95eb7ac7166f0aa4 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 28 Oct 2021 13:35:10 +0100 Subject: [PATCH 022/305] rename method in apicompat --- src/Avalonia.Input/ApiCompatBaseline.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Input/ApiCompatBaseline.txt b/src/Avalonia.Input/ApiCompatBaseline.txt index 221ef63476..270c5305e5 100644 --- a/src/Avalonia.Input/ApiCompatBaseline.txt +++ b/src/Avalonia.Input/ApiCompatBaseline.txt @@ -3,7 +3,7 @@ MembersMustExist : Member 'public Avalonia.Platform.IPlatformHandle Avalonia.Inp MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.Gestures.DoubleTappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.Gestures.RightTappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.Gestures.TappedEvent' does not exist in the implementation but it does exist in the contract. -InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.IFocusManager.ClearFocusScope(Avalonia.Input.IFocusScope)' is present in the implementation but not in the contract. +InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Input.IFocusManager.RemoveFocusScope(Avalonia.Input.IFocusScope)' is present in the implementation but not in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.InputElement.DoubleTappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public Avalonia.Interactivity.RoutedEvent Avalonia.Interactivity.RoutedEvent Avalonia.Input.InputElement.TappedEvent' does not exist in the implementation but it does exist in the contract. MembersMustExist : Member 'public void Avalonia.Input.InputElement.add_DoubleTapped(System.EventHandler)' does not exist in the implementation but it does exist in the contract. From 711ab49f0c3786e26d7dea4fedf714fbe4912e57 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 28 Oct 2021 13:38:08 +0100 Subject: [PATCH 023/305] discard var --- src/Avalonia.Input/FocusManager.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Avalonia.Input/FocusManager.cs b/src/Avalonia.Input/FocusManager.cs index 3e1ec84c03..f21edd7591 100644 --- a/src/Avalonia.Input/FocusManager.cs +++ b/src/Avalonia.Input/FocusManager.cs @@ -166,7 +166,7 @@ namespace Avalonia.Input { scope = scope ?? throw new ArgumentNullException(nameof(scope)); - if (_focusScopes.TryGetValue(scope, out var e)) + if (_focusScopes.TryGetValue(scope, out _)) { SetFocusedElement(scope, null); _focusScopes.Remove(scope); From 6f8f539a9fe9df86d753a4eba4158f1203ce8120 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 28 Oct 2021 14:20:27 +0100 Subject: [PATCH 024/305] prevent memory leak of mainwindow. --- .../ClassicDesktopStyleApplicationLifetime.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs index 2a42d99ac5..288939310c 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs @@ -122,12 +122,17 @@ namespace Avalonia.Controls.ApplicationLifetimes lifetimeEvents.ShutdownRequested += OnShutdownRequested; _cts = new CancellationTokenSource(); - MainWindow?.Show(); + ShowMainWindow(); Dispatcher.UIThread.MainLoop(_cts.Token); Environment.ExitCode = _exitCode; return _exitCode; } + private void ShowMainWindow() + { + MainWindow?.Show(); + } + public void Dispose() { if (_activeLifetime == this) From eb65760c51ece696539252ddd13bae137a0310f0 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 28 Oct 2021 15:07:56 +0100 Subject: [PATCH 025/305] add a comment explain JIT bug workaround. --- .../ClassicDesktopStyleApplicationLifetime.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs index 288939310c..a13813056b 100644 --- a/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs +++ b/src/Avalonia.Controls/ApplicationLifetimes/ClassicDesktopStyleApplicationLifetime.cs @@ -122,7 +122,10 @@ namespace Avalonia.Controls.ApplicationLifetimes lifetimeEvents.ShutdownRequested += OnShutdownRequested; _cts = new CancellationTokenSource(); - ShowMainWindow(); + ShowMainWindow(); // Note due to a bug in the JIT we wrap this in a method, otherwise MainWindow + // gets stuffed into a local var and can not be GCed until after the program stops. + // this method never exits until program end. + Dispatcher.UIThread.MainLoop(_cts.Token); Environment.ExitCode = _exitCode; return _exitCode; From 3fadc669b58a2ed5f5a6f3b8377cd6ff55a963f1 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 28 Oct 2021 22:25:31 +0100 Subject: [PATCH 026/305] ensure static resource can implicitly convert to brush when used in setters. --- .../MarkupExtensions/StaticResourceExtension.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs index 4ad68fc63e..db33b88cc3 100644 --- a/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs +++ b/src/Markup/Avalonia.Markup.Xaml/MarkupExtensions/StaticResourceExtension.cs @@ -5,6 +5,7 @@ using Avalonia.Controls; using Avalonia.Markup.Data; using Avalonia.Markup.Xaml.Converters; using Avalonia.Markup.Xaml.XamlIl.Runtime; +using Avalonia.Styling; namespace Avalonia.Markup.Xaml.MarkupExtensions { @@ -33,6 +34,11 @@ namespace Avalonia.Markup.Xaml.MarkupExtensions _ => null, }; + if (provideTarget.TargetObject is Setter setter) + { + targetType = setter.Property.PropertyType; + } + // Look upwards though the ambient context for IResourceHosts and IResourceProviders // which might be able to give us the resource. foreach (var e in stack.Parents) From 51ab3266dd27000496e372a8c32bffc61ba5cd51 Mon Sep 17 00:00:00 2001 From: Dan Walmsley Date: Thu, 28 Oct 2021 22:47:31 +0100 Subject: [PATCH 027/305] add a unit test. --- .../StaticResourceExtensionTests.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs index fb3fd6d7d4..340eac0d4f 100644 --- a/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs +++ b/tests/Avalonia.Markup.Xaml.UnitTests/MarkupExtensions/StaticResourceExtensionTests.cs @@ -512,6 +512,33 @@ namespace Avalonia.Markup.Xaml.UnitTests.MarkupExtensions var brush = (ISolidColorBrush)border.Background; Assert.Equal(0xff506070, brush.Color.ToUint32()); } + + [Fact] + public void Automatically_Converts_Color_To_SolidColorBrush_From_Setter() + { + using (StyledWindow()) + { + var xaml = @" + + + #ff506070 + + + + +