Skip to content

Commit

Permalink
Merge pull request #122 from atc-net/feature/Improve-DispatcherExtens…
Browse files Browse the repository at this point in the history
…ions

feat: Improve DispatcherExtensions
  • Loading branch information
davidkallesen authored Jun 7, 2024
2 parents efd7807 + 43a3a6f commit bfe09db
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 31 deletions.
4 changes: 2 additions & 2 deletions src/Atc.Wpf.Theming/Controls/Windows/NiceWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1045,7 +1045,7 @@ public void HideOverlay()
public void StoreFocus(
IInputElement? thisElement = null)
{
this.BeginInvoke(() =>
this.Invoke(() =>
{
restoreFocus = thisElement ?? restoreFocus ?? FocusManager.GetFocusedElement(this);
});
Expand All @@ -1058,7 +1058,7 @@ internal void RestoreFocus()
return;
}

this.BeginInvoke(() =>
this.Invoke(() =>
{
Keyboard.Focus(restoreFocus);
restoreFocus = null;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ public WindowButtonCommands()
CommandBindings.Add(new CommandBinding(System.Windows.SystemCommands.RestoreWindowCommand, RestoreWindow));
CommandBindings.Add(new CommandBinding(System.Windows.SystemCommands.CloseWindowCommand, CloseWindow));

this.BeginInvoke(
this.Invoke(
() =>
{
if (ParentWindow is null)
Expand Down
51 changes: 40 additions & 11 deletions src/Atc.Wpf/Extensions/DispatcherExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,17 @@
namespace System.Windows.Threading;

/// <summary>
/// Extension methods for Dispatcher.
/// Provides extension methods for the <see cref="Dispatcher"/> class to invoke actions based on thread access requirements.
/// </summary>
public static class DispatcherExtensions
{
/// <summary>
/// Invokes if required.
/// Invokes the specified action on the dispatcher thread if required, otherwise executes it directly.
/// </summary>
/// <param name="dispatcher">The dispatcher.</param>
/// <param name="action">The action.</param>
/// <param name="priority">The priority.</param>
/// <param name="dispatcher">The dispatcher to use for invoking the action.</param>
/// <param name="action">The action to be executed.</param>
/// <param name="priority">The priority at which the action is invoked, if required. The default is <see cref="DispatcherPriority.Normal"/>.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="dispatcher"/> or <paramref name="action"/> is null.</exception>
public static void InvokeIfRequired(
this Dispatcher dispatcher,
Action action,
Expand All @@ -31,12 +32,14 @@ public static void InvokeIfRequired(
}

/// <summary>
/// Begins the invoke if required.
/// Asynchronously invokes the specified action on the dispatcher thread if required, otherwise executes it directly.
/// </summary>
/// <param name="dispatcher">The dispatcher.</param>
/// <param name="action">The action.</param>
/// <param name="priority">The priority.</param>
public static void BeginInvokeIfRequired(
/// <param name="dispatcher">The dispatcher to use for invoking the action.</param>
/// <param name="action">The action to be executed.</param>
/// <param name="priority">The priority at which the action is invoked, if required. The default is <see cref="DispatcherPriority.Normal"/>.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="dispatcher"/> or <paramref name="action"/> is null.</exception>
public static async Task InvokeAsyncIfRequired(
this Dispatcher dispatcher,
Action action,
DispatcherPriority priority = DispatcherPriority.Normal)
Expand All @@ -50,7 +53,33 @@ public static void BeginInvokeIfRequired(
}
else
{
_ = dispatcher.BeginInvoke(action, priority);
await dispatcher.InvokeAsync(action, priority);
}
}

/// <summary>
/// Asynchronously begins invoking the specified action on the dispatcher thread if required, otherwise executes it directly.
/// </summary>
/// <param name="dispatcher">The dispatcher to use for invoking the action.</param>
/// <param name="action">The action to be executed.</param>
/// <param name="priority">The priority at which the action is invoked, if required. The default is <see cref="DispatcherPriority.Normal"/>.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="dispatcher"/> or <paramref name="action"/> is null.</exception>
public static async Task BeginInvokeIfRequired(
this Dispatcher dispatcher,
Action action,
DispatcherPriority priority = DispatcherPriority.Normal)
{
ArgumentNullException.ThrowIfNull(dispatcher);
ArgumentNullException.ThrowIfNull(action);

if (dispatcher.CheckAccess())
{
action();
}
else
{
await dispatcher.BeginInvoke(action, priority);
}
}
}
64 changes: 47 additions & 17 deletions src/Atc.Wpf/Extensions/DispatcherObjectExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,41 @@
namespace System.Windows.Threading;

/// <summary>
/// Extension methods for DispatcherObject.
/// Provides extension methods for the <see cref="DispatcherObject"/> class to invoke actions based on thread access requirements.
/// </summary>
public static class DispatcherObjectExtensions
{
/// <summary>
/// Invokes the specified function on the dispatcher thread if required, otherwise executes it directly.
/// </summary>
/// <typeparam name="T">The type of the result returned by the function.</typeparam>
/// <param name="dispatcherObject">The dispatcher object to use for invoking the function.</param>
/// <param name="func">The function to be executed.</param>
/// <returns>The result of the function execution.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="dispatcherObject"/> or <paramref name="func"/> is null.</exception>
public static T Invoke<T>(
this DispatcherObject dispatcherObject,
Func<T> func)
{
ArgumentNullException.ThrowIfNull(dispatcherObject);
ArgumentNullException.ThrowIfNull(func);

if (dispatcherObject.Dispatcher.CheckAccess())
{
return func();
}

return dispatcherObject.Dispatcher.Invoke(func);
return dispatcherObject.Dispatcher.CheckAccess()
? func()
: dispatcherObject.Dispatcher.Invoke(func);
}

/// <summary>
/// Invokes the specified action on the dispatcher thread if required, otherwise executes it directly.
/// </summary>
/// <param name="dispatcherObject">The dispatcher object to use for invoking the action.</param>
/// <param name="invokeAction">The action to be executed.</param>
/// <param name="priority">The priority at which the action is invoked, if required. The default is <see cref="DispatcherPriority.Normal"/>.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="dispatcherObject"/> or <paramref name="invokeAction"/> is null.</exception>
public static void Invoke(
this DispatcherObject dispatcherObject,
Action invokeAction)
Action invokeAction,
DispatcherPriority priority = DispatcherPriority.Normal)
{
ArgumentNullException.ThrowIfNull(dispatcherObject);
ArgumentNullException.ThrowIfNull(invokeAction);
Expand All @@ -34,16 +47,17 @@ public static void Invoke(
}
else
{
dispatcherObject.Dispatcher.Invoke(invokeAction);
dispatcherObject.Dispatcher.Invoke(invokeAction, priority);
}
}

/// <summary>
/// Runs the on UI thread.
/// Runs the specified action on the UI thread.
/// </summary>
/// <param name="dispatcherObject">The dispatcher object.</param>
/// <param name="invokeAction">The action to invoke.</param>
/// <param name="priority">The priority.</param>
/// <param name="dispatcherObject">The dispatcher object to use for invoking the action.</param>
/// <param name="invokeAction">The action to be executed.</param>
/// <param name="priority">The priority at which the action is invoked. The default is <see cref="DispatcherPriority.Normal"/>.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="dispatcherObject"/> or <paramref name="invokeAction"/> is null.</exception>
public static void RunOnUiThread(
this DispatcherObject dispatcherObject,
Action invokeAction,
Expand All @@ -52,20 +66,36 @@ public static void RunOnUiThread(
ArgumentNullException.ThrowIfNull(dispatcherObject);
ArgumentNullException.ThrowIfNull(invokeAction);

BeginInvoke(dispatcherObject, invokeAction, priority);
TaskHelper.FireAndForget(() => _ = dispatcherObject.BeginInvoke(invokeAction, priority));
}

public static void BeginInvoke(
/// <summary>
/// Asynchronously begins invoking the specified action on the dispatcher thread if required, otherwise executes it directly.
/// </summary>
/// <param name="dispatcherObject">The dispatcher object to use for invoking the action.</param>
/// <param name="invokeAction">The action to be executed.</param>
/// <param name="priority">The priority at which the action is invoked, if required. The default is <see cref="DispatcherPriority.Normal"/>.</param>
/// <returns>A task representing the asynchronous operation.</returns>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="dispatcherObject"/> or <paramref name="invokeAction"/> is null.</exception>
public static Task BeginInvoke(
this DispatcherObject dispatcherObject,
Action invokeAction,
DispatcherPriority priority = DispatcherPriority.Normal)
{
ArgumentNullException.ThrowIfNull(dispatcherObject);
ArgumentNullException.ThrowIfNull(invokeAction);

dispatcherObject.Dispatcher?.BeginInvokeIfRequired(invokeAction, priority);
return dispatcherObject.Dispatcher.BeginInvokeIfRequired(invokeAction, priority);
}

/// <summary>
/// Asynchronously begins invoking the specified action on the dispatcher thread if required, otherwise executes it directly, passing the dispatcher object as a parameter.
/// </summary>
/// <typeparam name="T">The type of the dispatcher object.</typeparam>
/// <param name="dispatcherObject">The dispatcher object to use for invoking the action.</param>
/// <param name="invokeAction">The action to be executed, which takes the dispatcher object as a parameter.</param>
/// <param name="priority">The priority at which the action is invoked, if required. The default is <see cref="DispatcherPriority.Normal"/>.</param>
/// <exception cref="ArgumentNullException">Thrown if <paramref name="dispatcherObject"/> or <paramref name="invokeAction"/> is null.</exception>
public static void BeginInvoke<T>(
this T dispatcherObject,
Action<T> invokeAction,
Expand All @@ -75,6 +105,6 @@ public static void BeginInvoke<T>(
ArgumentNullException.ThrowIfNull(dispatcherObject);
ArgumentNullException.ThrowIfNull(invokeAction);

_ = dispatcherObject.Dispatcher?.BeginInvoke(priority, new Action(() => invokeAction(dispatcherObject)));
_ = dispatcherObject.Dispatcher.BeginInvoke(priority, new Action(() => invokeAction(dispatcherObject)));
}
}

0 comments on commit bfe09db

Please sign in to comment.