Skip to content
Merged
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
26 changes: 24 additions & 2 deletions DialogHost.Avalonia/DialogClosingEventArgs.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,25 @@ namespace DialogHostAvalonia;
/// <summary>
/// Event args contains info about dialog closing
/// </summary>
public class DialogClosingEventArgs(DialogSession session, RoutedEvent routedEvent) : RoutedEventArgs(routedEvent) {
public class DialogClosingEventArgs(DialogSession session, RoutedEvent routedEvent, bool canBeCancelled)
: RoutedEventArgs(routedEvent) {
/// <inheritdoc />
[Obsolete("Use constructor with canBeCancelled parameter")]
public DialogClosingEventArgs(DialogSession session, RoutedEvent routedEvent) : this(session, routedEvent, true) {
}

/// <summary>
/// Cancel the close.
/// </summary>
public void Cancel() => IsCancelled = true;
public void Cancel() {
if (!CanBeCancelled) {
throw new InvalidOperationException(
$"Cannot cancel dialog closing after {nameof(DialogHost)}.{nameof(DialogHost.IsOpen)} " +
$"property has been set to {bool.FalseString}");
}

IsCancelled = true;
}

/// <summary>
/// Indicates if the close has already been cancelled.
Expand All @@ -26,4 +40,12 @@ public class DialogClosingEventArgs(DialogSession session, RoutedEvent routedEve
/// Allows interaction with the current dialog session.
/// </summary>
public DialogSession Session { get; } = session ?? throw new ArgumentNullException(nameof(session));

/// <summary>
/// Indicates if the close can be canceled.
/// </summary>
/// <remarks>
/// Typically this is <c>true</c> unless closing is triggered by setting <see cref="DialogHost.IsOpen"/> to <c>false</c>.
/// </remarks>
public bool CanBeCancelled { get; } = canBeCancelled;
}
40 changes: 10 additions & 30 deletions DialogHost.Avalonia/DialogHost.axaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -687,11 +687,13 @@ private void IsOpenPropertyChangedCallback(bool newValue) {
OnDialogOpened(dialogOpenedEventArgs);
DialogOpenedCallback?.Invoke(this, dialogOpenedEventArgs);
CurrentSession?.ShowOpened(this, dialogOpenedEventArgs);

// dialogHost._overlayPopupHost?.ConfigurePosition(dialogHost._root, PlacementMode.AnchorAndGravity, new Point());
}
else {
RemoveAllHost();
for (var i = _overlayPopupHosts.Count - 1; i >= 0; i--)
{
var session = _overlayPopupHosts[i].Session;
InternalClose(session, session.CloseParameter, false);
}

_restoreFocusDialogClose?.Focus();
}
Expand Down Expand Up @@ -799,25 +801,9 @@ public void RemoveDispose(DialogOverlayPopupHost host) {
return host.DialogTaskCompletionSource;
}

private void RemoveHost(DialogOverlayPopupHost? host) {
if (host == null) {
return;
}

var session = host.Session;
if (!session.IsEnded) {
session.Close(session.CloseParameter);
return;
}

//DialogSession.Close may attempt to cancel the closing of the dialog.
//When the dialog is closed in this manner it is not valid
if (!session.IsEnded) {
throw new InvalidOperationException($"Cannot cancel dialog closing after {nameof(IsOpen)} property has been set to {bool.FalseString}");
}

private void RemoveHost(DialogOverlayPopupHost host) {
//NB: _dialogTaskCompletionSource is only set in the case where the dialog is shown with Show
host.DialogTaskCompletionSource.TrySetResult(session.CloseParameter);
host.DialogTaskCompletionSource.TrySetResult(host.Session.CloseParameter);
host.IsOpen = false;
host.Content = null;

Expand All @@ -830,12 +816,6 @@ private void RemoveHost(DialogOverlayPopupHost? host) {
}
}

private void RemoveAllHost() {
foreach (var host in _overlayPopupHosts.ToArray().Reverse()) {
RemoveHost(host);
}
}

private void ContentCoverGrid_OnPointerReleased(object sender, PointerReleasedEventArgs e) {
if (CloseOnClickAway && CurrentSession != null) {
InternalClose(CloseOnClickAwayParameter);
Expand Down Expand Up @@ -873,18 +853,18 @@ public event EventHandler<DialogClosingEventArgs> DialogClosing {
internal void InternalClose(object? parameter) {
var session = CurrentSession ?? throw new InvalidOperationException($"{nameof(DialogHost)} does not have a current session");

InternalClose(session, parameter);
InternalClose(session, parameter, true);
}

internal void InternalClose(DialogSession session, object? parameter) {
internal void InternalClose(DialogSession session, object? parameter, bool canBeCancelled) {
session.CloseParameter = parameter;
session.IsEnded = true;

//multiple ways of calling back that the dialog is closing:
// * routed event
// * straight forward IsOpen dependency property
// * handler provided to the async show method
var dialogClosingEventArgs = new DialogClosingEventArgs(session, DialogClosingEvent);
var dialogClosingEventArgs = new DialogClosingEventArgs(session, DialogClosingEvent, canBeCancelled);
OnDialogClosing(dialogClosingEventArgs);
DialogClosingCallback?.Invoke(this, dialogClosingEventArgs);
session.ShowClosing(this, dialogClosingEventArgs);
Expand Down
4 changes: 2 additions & 2 deletions DialogHost.Avalonia/DialogSession.cs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ public void Close()
{
if (IsEnded) throw new InvalidOperationException("Dialog session has ended.");

_owner.InternalClose(this, null);
_owner.InternalClose(this, null, true);
}

/// <summary>
Expand All @@ -70,7 +70,7 @@ public void Close(object? parameter)
{
if (IsEnded) throw new InvalidOperationException("Dialog session has ended.");

_owner.InternalClose(this, parameter);
_owner.InternalClose(this, parameter, true);
}

internal void ShowOpened(object obj, DialogOpenedEventArgs args) {
Expand Down