Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 111 additions & 36 deletions src/WindowsFormsLifetime/FormProvider.cs
Original file line number Diff line number Diff line change
@@ -1,42 +1,7 @@
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection;

namespace WindowsFormsLifetime;

public interface IFormProvider
{
/// <summary>
/// Gets the requested form type and ensures it is created on the UI thread.
/// </summary>
/// <typeparam name="T">The form type to get.</typeparam>
/// <returns>An instance of the form, asynchronously.</returns>
Task<T> GetFormAsync<T>() where T : Form;

/// <summary>
/// Gets the requested form type and ensures it is created on the UI thread. Creates the form in the given scope.
/// </summary>
/// <typeparam name="T">The form type to get.</typeparam>
/// <param name="scope">The scope in which the form should be created.</param>
/// <returns>An instance of the form, asynchronously.</returns>
Task<T> GetFormAsync<T>(IServiceScope scope) where T : Form;

Task<Form> GetMainFormAsync();

/// <summary>
/// Gets the requested form type on the current thread. Should only be called on the UI thread. All scoped and transient dependencies will be disposed when the form is disposed.
/// </summary>
/// <typeparam name="T">The form type to get.</typeparam>
/// <returns>An instance of the form.</returns>
T GetForm<T>() where T : Form;

/// <summary>
/// Gets the requested form type on the current thread. Should only be called on the UI thread. Creates the form in the given scope.
/// </summary>
/// <typeparam name="T">The form type to get.</typeparam>
/// <param name="scope">The scope in which the form should be created.</param>
/// <returns>An instance of the form.</returns>
T GetForm<T>(IServiceScope scope) where T : Form;
}

public class FormProvider : IFormProvider
{
private readonly SemaphoreSlim _semaphore = new(1, 1);
Expand Down Expand Up @@ -67,6 +32,38 @@ public async Task<T> GetFormAsync<T>()
return form;
}

/// <inheritdoc />
public async Task<TForm> GetFormAsync<TForm, T1>(T1 param1) where TForm : Form
=> await CreateFormAsyncWithParameters<TForm>(param1);

/// <inheritdoc />
public async Task<TForm> GetFormAsync<TForm, T1, T2>(T1 param1, T2 param2) where TForm : Form
=> await CreateFormAsyncWithParameters<TForm>(param1, param2);

/// <inheritdoc />
public async Task<TForm> GetFormAsync<TForm, T1, T2, T3>(T1 param1, T2 param2, T3 param3) where TForm : Form
=> await CreateFormAsyncWithParameters<TForm>(param1, param2, param3);

/// <inheritdoc />
public async Task<TForm> GetFormAsync<TForm, T1, T2, T3, T4>(T1 param1, T2 param2, T3 param3, T4 param4) where TForm : Form
=> await CreateFormAsyncWithParameters<TForm>(param1, param2, param3, param4);

/// <inheritdoc />
public async Task<TForm> GetFormAsync<TForm, T1, T2, T3, T4, T5>(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5) where TForm : Form
=> await CreateFormAsyncWithParameters<TForm>(param1, param2, param3, param4, param5);

/// <inheritdoc />
public async Task<TForm> GetFormAsync<TForm, T1, T2, T3, T4, T5, T6>(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6) where TForm : Form
=> await CreateFormAsyncWithParameters<TForm>(param1, param2, param3, param4, param5, param6);

/// <inheritdoc />
public async Task<TForm> GetFormAsync<TForm, T1, T2, T3, T4, T5, T6, T7>(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6, T7 param7) where TForm : Form
=> await CreateFormAsyncWithParameters<TForm>(param1, param2, param3, param4, param5, param6, param7);

/// <inheritdoc />
public async Task<TForm> GetFormAsync<TForm, T1, T2, T3, T4, T5, T6, T7, T8>(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6, T7 param7, T8 param8) where TForm : Form
=> await CreateFormAsyncWithParameters<TForm>(param1, param2, param3, param4, param5, param6, param7, param8);

public async Task<T> GetFormAsync<T>(IServiceScope scope) where T : Form
{
// We are throttling this because there is only one gui thread
Expand Down Expand Up @@ -110,8 +107,86 @@ public T GetForm<T>() where T : Form
return form;
}

/// <inheritdoc />
public TForm GetForm<TForm, T1>(T1 param1) where TForm : Form
=> CreateFormWithParameters<TForm>(param1);

/// <inheritdoc />
public TForm GetForm<TForm, T1, T2>(T1 param1, T2 param2) where TForm : Form
=> CreateFormWithParameters<TForm>(param1, param2);

/// <inheritdoc />
public TForm GetForm<TForm, T1, T2, T3>(T1 param1, T2 param2, T3 param3) where TForm : Form
=> CreateFormWithParameters<TForm>(param1, param2, param3);

/// <inheritdoc />
public TForm GetForm<TForm, T1, T2, T3, T4>(T1 param1, T2 param2, T3 param3, T4 param4) where TForm : Form
=> CreateFormWithParameters<TForm>(param1, param2, param3, param4);

/// <inheritdoc />
public TForm GetForm<TForm, T1, T2, T3, T4, T5>(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5) where TForm : Form
=> CreateFormWithParameters<TForm>(param1, param2, param3, param4, param5);

/// <inheritdoc />
public TForm GetForm<TForm, T1, T2, T3, T4, T5, T6>(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6) where TForm : Form
=> CreateFormWithParameters<TForm>(param1, param2, param3, param4, param5, param6);

/// <inheritdoc />
public TForm GetForm<TForm, T1, T2, T3, T4, T5, T6, T7>(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6, T7 param7) where TForm : Form
=> CreateFormWithParameters<TForm>(param1, param2, param3, param4, param5, param6, param7);

/// <inheritdoc />
public TForm GetForm<TForm, T1, T2, T3, T4, T5, T6, T7, T8>(T1 param1, T2 param2, T3 param3, T4 param4, T5 param5, T6 param6, T7 param7, T8 param8) where TForm : Form
=> CreateFormWithParameters<TForm>(param1, param2, param3, param4, param5, param6, param7, param8);

public T GetForm<T>(IServiceScope scope) where T : Form
=> scope.ServiceProvider.GetService<T>();

public void Dispose() => _semaphore?.Dispose();

private TForm CreateFormWithParameters<TForm>(params object[] parameters) where TForm : Form
{
return CreateFormWithScope(scope => ActivatorUtilities.CreateInstance<TForm>(scope.ServiceProvider, parameters));
}

private TForm CreateFormWithScope<TForm>(Func<IServiceScope, TForm> formFactory) where TForm : Form
{
TForm form;
var scope = _serviceScopeFactory.CreateScope();
try
{
form = formFactory(scope);
if (form == null)
{
scope.Dispose();
}
else
{
form.Disposed += (_, _) => scope.Dispose();
}
}
catch
{
scope.Dispose();
throw;
}

return form;
}

private async Task<TForm> CreateFormAsyncWithParameters<TForm>(params object[] parameters) where TForm : Form
{
await _semaphore.WaitAsync();

try
{
var form = await _syncContextManager.SynchronizationContext.InvokeAsync(() =>
CreateFormWithParameters<TForm>(parameters));
return form;
}
finally
{
_semaphore.Release();
}
}
}
Loading