Browse Source

Merge branch 'master' into colorspectrum

pull/7842/head
robloo 4 years ago
parent
commit
9a5b3ef9a4
  1. 2
      build/DevAnalyzers.props
  2. 5
      samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj
  3. 7
      samples/ControlCatalog.NetCore/rd.xml
  4. 3
      src/Avalonia.Base/ApiCompatBaseline.txt
  5. 2
      src/Avalonia.Base/Threading/AvaloniaScheduler.cs
  6. 12
      src/Avalonia.Base/Threading/Dispatcher.cs
  7. 97
      src/Avalonia.Base/Threading/DispatcherPriority.cs
  8. 4
      src/Avalonia.Base/Threading/DispatcherTimer.cs
  9. 12
      src/Avalonia.Base/Threading/IDispatcher.cs
  10. 54
      src/Avalonia.Controls/Generators/TreeContainerIndex.cs
  11. 3
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
  12. 12
      tests/Avalonia.UnitTests/ImmediateDispatcher.cs

2
build/DevAnalyzers.props

@ -1,6 +1,6 @@
<Project DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<ProjectReference Include="$(MSBuildThisFileDirectory)..\src\Tools\DevAnalyzers\DevAnalyzers.csproj"
<ProjectReference Include="$(MSBuildThisFileDirectory)..\src\tools\DevAnalyzers\DevAnalyzers.csproj"
PrivateAssets="all"
ReferenceOutputAssembly="false"
OutputItemType="Analyzer"

5
samples/ControlCatalog.NetCore/ControlCatalog.NetCore.csproj

@ -6,7 +6,7 @@
<TargetLatestRuntimePatch>true</TargetLatestRuntimePatch>
</PropertyGroup>
<PropertyGroup Condition="'$(RunAotCompilation)' == 'true'">
<PropertyGroup Condition="'$(RunNativeAotCompilation)' == 'true'">
<IlcTrimMetadata>true</IlcTrimMetadata>
<RestoreAdditionalProjectSources>https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet7/nuget/v3/index.json</RestoreAdditionalProjectSources>
<NativeAotCompilerVersion>7.0.0-*</NativeAotCompilerVersion>
@ -22,12 +22,11 @@
<PackageReference Include="Avalonia.Angle.Windows.Natives" Version="2.1.0.2020091801" />
</ItemGroup>
<ItemGroup Condition="'$(RunAotCompilation)' == 'true'">
<ItemGroup Condition="'$(RunNativeAotCompilation)' == 'true'">
<PackageReference Include="Microsoft.DotNet.ILCompiler" Version="$(NativeAotCompilerVersion)" />
<!-- Cross-compilation for Windows x64-arm64 and Linux x64-arm64 -->
<PackageReference Condition="'$(RuntimeIdentifier)'=='win-arm64'" Include="runtime.win-x64.Microsoft.DotNet.ILCompiler" Version="$(NativeAotCompilerVersion)" />
<PackageReference Condition="'$(RuntimeIdentifier)'=='linux-arm64'" Include="runtime.linux-x64.Microsoft.DotNet.ILCompiler" Version="$(NativeAotCompilerVersion)" />
<RdXmlFile Include="rd.xml" />
</ItemGroup>
<PropertyGroup>

7
samples/ControlCatalog.NetCore/rd.xml

@ -1,7 +0,0 @@
<Directives>
<Application>
<Assembly Name="ControlCatalog" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Themes.Default" Dynamic="Required All"></Assembly>
<Assembly Name="Avalonia.Themes.Fluent" Dynamic="Required All"></Assembly>
</Application>
</Directives>

3
src/Avalonia.Base/ApiCompatBaseline.txt

@ -1,3 +1,4 @@
Compat issues with assembly Avalonia.Base:
MembersMustExist : Member 'public System.Int32 System.Int32 Avalonia.Threading.DispatcherPriority.value__' does not exist in the implementation but it does exist in the contract.
InterfacesShouldHaveSameMembers : Interface member 'public void Avalonia.Threading.IDispatcher.Post<T>(System.Action<T>, T, Avalonia.Threading.DispatcherPriority)' is present in the implementation but not in the contract.
Total Issues: 1
Total Issues: 2

2
src/Avalonia.Base/Threading/AvaloniaScheduler.cs

@ -46,7 +46,7 @@ namespace Avalonia.Threading
{
composite.Add(action(this, state));
}
}, DispatcherPriority.DataBind);
}, DispatcherPriority.Background);
composite.Add(cancellation);

12
src/Avalonia.Base/Threading/Dispatcher.cs

@ -83,42 +83,42 @@ namespace Avalonia.Threading
_jobRunner.HasJobsWithPriority(minimumPriority);
/// <inheritdoc/>
public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
public Task InvokeAsync(Action action, DispatcherPriority priority = default)
{
_ = action ?? throw new ArgumentNullException(nameof(action));
return _jobRunner.InvokeAsync(action, priority);
}
/// <inheritdoc/>
public Task<TResult> InvokeAsync<TResult>(Func<TResult> function, DispatcherPriority priority = DispatcherPriority.Normal)
public Task<TResult> InvokeAsync<TResult>(Func<TResult> function, DispatcherPriority priority = default)
{
_ = function ?? throw new ArgumentNullException(nameof(function));
return _jobRunner.InvokeAsync(function, priority);
}
/// <inheritdoc/>
public Task InvokeAsync(Func<Task> function, DispatcherPriority priority = DispatcherPriority.Normal)
public Task InvokeAsync(Func<Task> function, DispatcherPriority priority = default)
{
_ = function ?? throw new ArgumentNullException(nameof(function));
return _jobRunner.InvokeAsync(function, priority).Unwrap();
}
/// <inheritdoc/>
public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> function, DispatcherPriority priority = DispatcherPriority.Normal)
public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> function, DispatcherPriority priority = default)
{
_ = function ?? throw new ArgumentNullException(nameof(function));
return _jobRunner.InvokeAsync(function, priority).Unwrap();
}
/// <inheritdoc/>
public void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
public void Post(Action action, DispatcherPriority priority = default)
{
_ = action ?? throw new ArgumentNullException(nameof(action));
_jobRunner.Post(action, priority);
}
/// <inheritdoc/>
public void Post<T>(Action<T> action, T arg, DispatcherPriority priority = DispatcherPriority.Normal)
public void Post<T>(Action<T> action, T arg, DispatcherPriority priority = default)
{
_ = action ?? throw new ArgumentNullException(nameof(action));
_jobRunner.Post(action, arg, priority);

97
src/Avalonia.Base/Threading/DispatcherPriority.cs

@ -1,74 +1,121 @@
using System;
namespace Avalonia.Threading
{
/// <summary>
/// Defines the priorities with which jobs can be invoked on a <see cref="Dispatcher"/>.
/// </summary>
// TODO: These are copied from WPF - many won't apply to Avalonia.
public enum DispatcherPriority
public readonly struct DispatcherPriority : IEquatable<DispatcherPriority>, IComparable<DispatcherPriority>
{
/// <summary>
/// The integer value of the priority
/// </summary>
public int Value { get; }
private DispatcherPriority(int value)
{
Value = value;
}
/// <summary>
/// Minimum possible priority
/// </summary>
MinValue = 1,
public static readonly DispatcherPriority MinValue = new(0);
/// <summary>
/// The job will be processed when the system is idle.
/// </summary>
SystemIdle = 1,
[Obsolete("WPF compatibility")] public static readonly DispatcherPriority SystemIdle = MinValue;
/// <summary>
/// The job will be processed when the application is idle.
/// </summary>
ApplicationIdle = 2,
[Obsolete("WPF compatibility")] public static readonly DispatcherPriority ApplicationIdle = MinValue;
/// <summary>
/// The job will be processed after background operations have completed.
/// </summary>
ContextIdle = 3,
[Obsolete("WPF compatibility")] public static readonly DispatcherPriority ContextIdle = MinValue;
/// <summary>
/// The job will be processed after other non-idle operations have completed.
/// The job will be processed with normal priority.
/// </summary>
Background = 4,
public static readonly DispatcherPriority Normal = MinValue;
/// <summary>
/// The job will be processed with the same priority as input.
/// The job will be processed after other non-idle operations have completed.
/// </summary>
Input = 5,
public static readonly DispatcherPriority Background = new(1);
/// <summary>
/// The job will be processed after layout and render but before input.
/// The job will be processed with the same priority as input.
/// </summary>
Loaded = 6,
public static readonly DispatcherPriority Input = new(2);
/// <summary>
/// The job will be processed with the same priority as render.
/// The job will be processed after layout and render but before input.
/// </summary>
Render = 7,
public static readonly DispatcherPriority Loaded = new(3);
/// <summary>
/// The job will be processed with the same priority as render.
/// </summary>
Layout = 8,
public static readonly DispatcherPriority Render = new(5);
/// <summary>
/// The job will be processed with the same priority as data binding.
/// The job will be processed with the same priority as render.
/// </summary>
DataBind = 9,
public static readonly DispatcherPriority Layout = new(6);
/// <summary>
/// The job will be processed with normal priority.
/// The job will be processed with the same priority as data binding.
/// </summary>
Normal = 10,
[Obsolete("WPF compatibility")] public static readonly DispatcherPriority DataBind = MinValue;
/// <summary>
/// The job will be processed before other asynchronous operations.
/// </summary>
Send = 11,
public static readonly DispatcherPriority Send = new(7);
/// <summary>
/// Maximum possible priority
/// </summary>
MaxValue = 11
public static readonly DispatcherPriority MaxValue = Send;
// Note: unlike ctor this one is validating
public static DispatcherPriority FromValue(int value)
{
if (value < MinValue.Value || value > MaxValue.Value)
throw new ArgumentOutOfRangeException(nameof(value));
return new DispatcherPriority(value);
}
public static implicit operator int(DispatcherPriority priority) => priority.Value;
public static implicit operator DispatcherPriority(int value) => FromValue(value);
/// <inheritdoc />
public bool Equals(DispatcherPriority other) => Value == other.Value;
/// <inheritdoc />
public override bool Equals(object? obj) => obj is DispatcherPriority other && Equals(other);
/// <inheritdoc />
public override int GetHashCode() => Value.GetHashCode();
public static bool operator ==(DispatcherPriority left, DispatcherPriority right) => left.Value == right.Value;
public static bool operator !=(DispatcherPriority left, DispatcherPriority right) => left.Value != right.Value;
public static bool operator <(DispatcherPriority left, DispatcherPriority right) => left.Value < right.Value;
public static bool operator >(DispatcherPriority left, DispatcherPriority right) => left.Value > right.Value;
public static bool operator <=(DispatcherPriority left, DispatcherPriority right) => left.Value <= right.Value;
public static bool operator >=(DispatcherPriority left, DispatcherPriority right) => left.Value >= right.Value;
/// <inheritdoc />
public int CompareTo(DispatcherPriority other) => Value.CompareTo(other.Value);
}
}
}

4
src/Avalonia.Base/Threading/DispatcherTimer.cs

@ -123,7 +123,7 @@ namespace Avalonia.Threading
/// <param name="interval">The interval at which to tick.</param>
/// <param name="priority">The priority to use.</param>
/// <returns>An <see cref="IDisposable"/> used to cancel the timer.</returns>
public static IDisposable Run(Func<bool> action, TimeSpan interval, DispatcherPriority priority = DispatcherPriority.Normal)
public static IDisposable Run(Func<bool> action, TimeSpan interval, DispatcherPriority priority = default)
{
var timer = new DispatcherTimer(priority) { Interval = interval };
@ -152,7 +152,7 @@ namespace Avalonia.Threading
public static IDisposable RunOnce(
Action action,
TimeSpan interval,
DispatcherPriority priority = DispatcherPriority.Normal)
DispatcherPriority priority = default)
{
interval = (interval != TimeSpan.Zero) ? interval : TimeSpan.FromTicks(1);

12
src/Avalonia.Base/Threading/IDispatcher.cs

@ -24,7 +24,7 @@ namespace Avalonia.Threading
/// </summary>
/// <param name="action">The method.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal);
void Post(Action action, DispatcherPriority priority = default);
/// <summary>
/// Posts an action that will be invoked on the dispatcher thread.
@ -33,7 +33,7 @@ namespace Avalonia.Threading
/// <param name="action">The method to call.</param>
/// <param name="arg">The argument of method to call.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
void Post<T>(Action<T> action, T arg, DispatcherPriority priority = DispatcherPriority.Normal);
void Post<T>(Action<T> action, T arg, DispatcherPriority priority = default);
/// <summary>
/// Invokes a action on the dispatcher thread.
@ -41,7 +41,7 @@ namespace Avalonia.Threading
/// <param name="action">The method.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
/// <returns>A task that can be used to track the method's execution.</returns>
Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal);
Task InvokeAsync(Action action, DispatcherPriority priority = default);
/// <summary>
/// Invokes a method on the dispatcher thread.
@ -49,7 +49,7 @@ namespace Avalonia.Threading
/// <param name="function">The method.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
/// <returns>A task that can be used to track the method's execution.</returns>
Task<TResult> InvokeAsync<TResult>(Func<TResult> function, DispatcherPriority priority = DispatcherPriority.Normal);
Task<TResult> InvokeAsync<TResult>(Func<TResult> function, DispatcherPriority priority = default);
/// <summary>
/// Queues the specified work to run on the dispatcher thread and returns a proxy for the
@ -58,7 +58,7 @@ namespace Avalonia.Threading
/// <param name="function">The work to execute asynchronously.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
/// <returns>A task that represents a proxy for the task returned by <paramref name="function"/>.</returns>
Task InvokeAsync(Func<Task> function, DispatcherPriority priority = DispatcherPriority.Normal);
Task InvokeAsync(Func<Task> function, DispatcherPriority priority = default);
/// <summary>
/// Queues the specified work to run on the dispatcher thread and returns a proxy for the
@ -67,6 +67,6 @@ namespace Avalonia.Threading
/// <param name="function">The work to execute asynchronously.</param>
/// <param name="priority">The priority with which to invoke the method.</param>
/// <returns>A task that represents a proxy for the task returned by <paramref name="function"/>.</returns>
Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> function, DispatcherPriority priority = DispatcherPriority.Normal);
Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> function, DispatcherPriority priority = default);
}
}

54
src/Avalonia.Controls/Generators/TreeContainerIndex.cs

@ -15,6 +15,7 @@ namespace Avalonia.Controls.Generators
/// </remarks>
public class TreeContainerIndex
{
private readonly Dictionary<object, HashSet<IControl>> _itemToContainerSet = new Dictionary<object, HashSet<IControl>>();
private readonly Dictionary<object, IControl> _itemToContainer = new Dictionary<object, IControl>();
private readonly Dictionary<IControl, object> _containerToItem = new Dictionary<IControl, object>();
@ -45,14 +46,45 @@ namespace Avalonia.Controls.Generators
/// <param name="container">The item container.</param>
public void Add(object item, IControl container)
{
_itemToContainer.Add(item, container);
_itemToContainer[item] = container;
if (_itemToContainerSet.TryGetValue(item, out var set))
{
set.Add(container);
}
else
{
_itemToContainerSet.Add(item, new HashSet<IControl> { container });
}
_containerToItem.Add(container, item);
Materialized?.Invoke(
this,
this,
new ItemContainerEventArgs(new ItemContainerInfo(container, item, 0)));
}
/// <summary>
/// Removes a container from private collections.
/// </summary>
/// <param name="container">The item container.</param>
/// <param name="item">The DataContext object</param>
private void RemoveContainer(IControl container, object item)
{
if (_itemToContainerSet.TryGetValue(item, out var set))
{
set.Remove(container);
if (set.Count == 0)
{
_itemToContainerSet.Remove(item);
_itemToContainer.Remove(item);
}
else
{
_itemToContainer[item] = set.First();
}
}
}
/// <summary>
/// Removes a container from the index.
/// </summary>
@ -61,10 +93,10 @@ namespace Avalonia.Controls.Generators
{
var item = _containerToItem[container];
_containerToItem.Remove(container);
_itemToContainer.Remove(item);
RemoveContainer(container, item);
Dematerialized?.Invoke(
this,
this,
new ItemContainerEventArgs(new ItemContainerInfo(container, item, 0)));
}
@ -79,7 +111,7 @@ namespace Avalonia.Controls.Generators
{
var item = _containerToItem[container.ContainerControl];
_containerToItem.Remove(container.ContainerControl);
_itemToContainer.Remove(item);
RemoveContainer(container.ContainerControl, item);
}
Dematerialized?.Invoke(
@ -97,6 +129,14 @@ namespace Avalonia.Controls.Generators
if (item != null)
{
_itemToContainer.TryGetValue(item, out var result);
if (result == null)
{
_itemToContainerSet.TryGetValue(item, out var set);
if (set?.Count > 0)
{
return set.FirstOrDefault();
}
}
return result;
}
@ -113,6 +153,10 @@ namespace Avalonia.Controls.Generators
if (container != null)
{
_containerToItem.TryGetValue(container, out var result);
if (result != null)
{
_itemToContainer[result] = container;
}
return result;
}

3
src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs

@ -162,8 +162,7 @@ namespace Avalonia.Diagnostics.ViewModels
}
catch { }
},
TimeSpan.FromMilliseconds(0),
DispatcherPriority.ApplicationIdle);
TimeSpan.FromMilliseconds(0));
}
RaiseAndSetIfChanged(ref _content, value);

12
tests/Avalonia.UnitTests/ImmediateDispatcher.cs

@ -16,39 +16,39 @@ namespace Avalonia.UnitTests
}
/// <inheritdoc/>
public void Post(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
public void Post(Action action, DispatcherPriority priority)
{
action();
}
/// <inheritdoc/>
public void Post<T>(Action<T> action, T arg, DispatcherPriority priority = DispatcherPriority.Normal)
public void Post<T>(Action<T> action, T arg, DispatcherPriority priority)
{
action(arg);
}
/// <inheritdoc/>
public Task InvokeAsync(Action action, DispatcherPriority priority = DispatcherPriority.Normal)
public Task InvokeAsync(Action action, DispatcherPriority priority)
{
action();
return Task.CompletedTask;
}
/// <inheritdoc/>
public Task<TResult> InvokeAsync<TResult>(Func<TResult> function, DispatcherPriority priority = DispatcherPriority.Normal)
public Task<TResult> InvokeAsync<TResult>(Func<TResult> function, DispatcherPriority priority)
{
var result = function();
return Task.FromResult(result);
}
/// <inheritdoc/>
public Task InvokeAsync(Func<Task> function, DispatcherPriority priority = DispatcherPriority.Normal)
public Task InvokeAsync(Func<Task> function, DispatcherPriority priority)
{
return function();
}
/// <inheritdoc/>
public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> function, DispatcherPriority priority = DispatcherPriority.Normal)
public Task<TResult> InvokeAsync<TResult>(Func<Task<TResult>> function, DispatcherPriority priority)
{
return function();
}

Loading…
Cancel
Save