Browse Source

Merge pull request #7517 from AvaloniaUI/feature/struct-dispatcher-priorities

Make DispatcherPriority to be a struct with static readonly field values
pull/8014/head
Max Katz 4 years ago
committed by GitHub
parent
commit
532a07565d
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 3
      src/Avalonia.Base/ApiCompatBaseline.txt
  2. 2
      src/Avalonia.Base/Threading/AvaloniaScheduler.cs
  3. 12
      src/Avalonia.Base/Threading/Dispatcher.cs
  4. 97
      src/Avalonia.Base/Threading/DispatcherPriority.cs
  5. 4
      src/Avalonia.Base/Threading/DispatcherTimer.cs
  6. 12
      src/Avalonia.Base/Threading/IDispatcher.cs
  7. 3
      src/Avalonia.Diagnostics/Diagnostics/ViewModels/MainViewModel.cs
  8. 12
      tests/Avalonia.UnitTests/ImmediateDispatcher.cs

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);
}
}

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