< Summary

Information
Class: MyNet.UI.Dialogs.ContentDialogs.ContentDialogService
Assembly: MyNet.UI
File(s): https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/Dialogs/ContentDialogs/ContentDialogService.cs
Tag: 323_28699572109
Line coverage
96%
Covered lines: 63
Uncovered lines: 2
Coverable lines: 65
Total lines: 177
Line coverage: 96.9%
Branch coverage
85%
Covered branches: 12
Total branches: 14
Branch coverage: 85.7%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity Line coverage
.ctor(...)100%11100%
get_OpenedDialogs()100%11100%
get_HasOpenedDialogs()100%11100%
ShowAsync()100%11100%
ShowAsync()100%11100%
Create(...)100%210%
Create(...)100%210%
CloseAsync()50%22100%
BeginShow(...)100%22100%
CompleteLifecycleAsync()87.5%88100%
GetStrategy(...)100%22100%

File(s)

https://raw.githubusercontent.com/sandre58/MyNet/85372080fe102cd9ee155ceab49ae000e7f66103/src/MyNet.UI/Dialogs/ContentDialogs/ContentDialogService.cs

#LineLine coverage
 1// -----------------------------------------------------------------------
 2// <copyright file="ContentDialogService.cs" company="Stéphane ANDRE">
 3// Copyright (c) Stéphane ANDRE. All rights reserved.
 4// </copyright>
 5// -----------------------------------------------------------------------
 6
 7using System;
 8using System.Collections.Generic;
 9using System.Linq;
 10using System.Threading;
 11using System.Threading.Tasks;
 12
 13namespace MyNet.UI.Dialogs.ContentDialogs;
 14
 15/// <summary>
 16/// Default implementation of <see cref="IContentDialogService"/>.
 17/// Selects the appropriate <see cref="IDialogStrategy"/> via <c>CanHandle</c> / <c>Priority</c>
 18/// and manages the full dialog lifecycle (OnOpenedAsync → show → OnClosedAsync).
 19/// </summary>
 20public sealed class ContentDialogService(IEnumerable<IDialogStrategy> strategies) : IContentDialogService
 21{
 3322    private readonly Lock _sync = new();
 3323    private readonly List<IDialog> _openedDialogs = [];
 3324    private readonly Dictionary<IDialog, ActiveDialog> _activeDialogs = [];
 25
 26    /// <inheritdoc />
 27    public event EventHandler<ContentDialogLifecycleEventArgs>? DialogOpened;
 28
 29    /// <inheritdoc />
 30    public event EventHandler<ContentDialogLifecycleEventArgs>? DialogClosed;
 31
 32    /// <inheritdoc />
 33    public IReadOnlyList<IDialog> OpenedDialogs
 34    {
 35        get
 336        {
 37            lock (_sync)
 38            {
 339                return _openedDialogs.ToList().AsReadOnly();
 40            }
 341        }
 42    }
 43
 44    /// <inheritdoc />
 45    public bool HasOpenedDialogs
 46    {
 47        get
 948        {
 49            lock (_sync)
 50            {
 951                return _openedDialogs.Count > 0;
 52            }
 953        }
 54    }
 55
 56    /// <inheritdoc />
 57    public async Task<DialogResult<bool>> ShowAsync(IDialog dialog, DialogOptions? options = null, CancellationToken can
 58    {
 1859        ArgumentNullException.ThrowIfNull(dialog);
 1860        cancellationToken.ThrowIfCancellationRequested();
 61
 1862        var resolvedOptions = DialogOptions.Resolve(dialog, options);
 1863        var strategy = GetStrategy(dialog, resolvedOptions);
 1564        BeginShow(dialog, strategy);
 65
 1566        await dialog.OnOpenedAsync().ConfigureAwait(false);
 67
 68        try
 69        {
 1570            cancellationToken.ThrowIfCancellationRequested();
 1571            return await strategy.ShowAsync(dialog, resolvedOptions, cancellationToken).ConfigureAwait(false);
 72        }
 73        finally
 74        {
 1575            await CompleteLifecycleAsync(dialog).ConfigureAwait(false);
 76        }
 1577    }
 78
 79    /// <inheritdoc />
 80    public async Task<DialogResult<TResult>> ShowAsync<TResult>(IDialog<TResult> dialog, DialogOptions? options = null, 
 81    {
 1282        ArgumentNullException.ThrowIfNull(dialog);
 1283        cancellationToken.ThrowIfCancellationRequested();
 84
 1285        var resolvedOptions = DialogOptions.Resolve(dialog, options);
 1286        var strategy = GetStrategy(dialog, resolvedOptions);
 1287        BeginShow(dialog, strategy);
 88
 1289        await dialog.OnOpenedAsync().ConfigureAwait(false);
 1290        var resultTask = dialog.GetResultAsync();
 91
 92        try
 93        {
 1294            cancellationToken.ThrowIfCancellationRequested();
 1295            await strategy.ShowAsync(dialog, resolvedOptions, cancellationToken).ConfigureAwait(false);
 96        }
 97        finally
 98        {
 1299            await CompleteLifecycleAsync(dialog).ConfigureAwait(false);
 100        }
 101
 12102        return await resultTask.ConfigureAwait(false);
 12103    }
 104
 105    /// <inheritdoc />
 0106    public IDialogBuilder Create(IDialog dialog) => new DialogBuilder(this, dialog);
 107
 108    /// <inheritdoc />
 0109    public IDialogBuilder<TResult> Create<TResult>(IDialog<TResult> dialog) => new DialogBuilder<TResult>(this, dialog);
 110
 111    /// <inheritdoc />
 112    public async Task CloseAsync(IDialog dialog)
 113    {
 3114        ArgumentNullException.ThrowIfNull(dialog);
 115
 116        IDialogStrategy strategy;
 117        lock (_sync)
 118        {
 3119            strategy = _activeDialogs.TryGetValue(dialog, out var active)
 3120                ? active.Strategy
 3121                : GetStrategy(dialog, null);
 3122        }
 123
 3124        await strategy.CloseAsync(dialog).ConfigureAwait(false);
 3125        await CompleteLifecycleAsync(dialog).ConfigureAwait(false);
 3126    }
 127
 128    private void BeginShow(IDialog dialog, IDialogStrategy strategy)
 27129    {
 130        lock (_sync)
 131        {
 27132            _openedDialogs.Add(dialog);
 27133            _activeDialogs[dialog] = new() { Strategy = strategy };
 27134        }
 135
 27136        DialogOpened?.Invoke(this, new(dialog));
 3137    }
 138
 139    private async Task CompleteLifecycleAsync(IDialog dialog)
 30140    {
 141        bool shouldNotifyClosed;
 142        lock (_sync)
 143        {
 30144            if (!_activeDialogs.TryGetValue(dialog, out var active) || active.LifecycleCompleted)
 145            {
 3146                return;
 147            }
 148
 27149            active.LifecycleCompleted = true;
 27150            _openedDialogs.Remove(dialog);
 27151            _activeDialogs.Remove(dialog);
 27152            shouldNotifyClosed = true;
 27153        }
 154
 27155        if (shouldNotifyClosed)
 156        {
 27157            await dialog.OnClosedAsync().ConfigureAwait(false);
 27158            DialogClosed?.Invoke(this, new(dialog));
 159        }
 30160    }
 161
 162    private IDialogStrategy GetStrategy(IDialog dialog, DialogOptions? options)
 30163        => strategies
 30164            .Where(s => s.CanHandle(dialog, options))
 30165            .OrderByDescending(s => s.Priority)
 30166            .FirstOrDefault()
 30167           ?? throw new InvalidOperationException(
 30168               $"No dialog strategy found for '{dialog.GetType().Name}'. Register an IDialogStrategy via AddDialogs() or
 169
 170    private sealed class ActiveDialog
 171    {
 172        public required IDialogStrategy Strategy { get; init; }
 173
 174        public bool LifecycleCompleted { get; set; }
 175    }
 176}
 177