Generic Dialogs API spec
See original GitHub issueI’ve had a couple requests for enhancements to the existing ContentDialog
functionality. As a result, I’m drafting up an API spec for generic dialogs. As ContentDialog
is a WinUI item (reverse engineered instead of ported, but still) I don’t want to modify the API in a way that makes it different to the upstream version other than bug fixes or minor feature additions.
The biggest issue from the comments is that the lack of button options in ContentDialog
make it somewhat limiting, something the old vista-style TaskDialog
solves (to an extent). This proposal, therefore, seeks a new control and API spec. Note that this is just an API spec to layout the general thought and get feedback of desired features - and is not yet a firm proposal or commitment.
EDIT: Final spec laid out here - PR created
public class TaskDialog : ContentControl
{
/// <summary>
/// Gets or sets the title of the dialog
/// </summary>
/// <remarks>
/// This is the window caption of the dialog displayed in the title bar. For platforms
/// where windowing is not supported, this property has no effect.
/// </remarks>
public string Title { get; set; }
/// <summary>
/// Gets or sets the dialog header text
/// </summary>
public string Header { get; set; }
/// <summary>
/// Gets or sets the dialog sub header text
/// </summary>
public string SubHeader { get; set; }
/// <summary>
/// Gets or sets the dialog Icon
/// </summary>
public IconSource IconSource { get; set; }
/// <summary>
/// Gets the list of buttons that display at the bottom of the TaskDialog
/// </summary>
public IList<TaskDialogButton> Buttons { get; set; }
/// <summary>
/// Gets the list of Commands displayed in the TaskDialog
/// </summary>
public IList<TaskDialogCommand> Commands { get; set; }
/// <summary>
/// Gets or sets the visibility of the Footer area
/// </summary>
public TaskDialogFooterVisibility FooterVisibility { get; set; }
/// <summary>
/// Gets or sets whether the footer is visible
/// </summary>
public bool IsFooterExpanded { get; set; }
/// <summary>
/// Gets or sets the footer content
/// </summary>
public object Footer { get; set; }
/// <summary>
/// Gets or sets the IDataTemplate for the footer content
/// </summary>
public IDataTemplate FooterTemplate { get; set; }
/// <summary>
/// Gets or sets whether this TaskDialog shows a progress bar
/// </summary>
public bool ShowProgressBar { get; set; }
/// <summary>
/// Gets or sets the root visual that should host this dialog
/// </summary>
/// <remarks>
/// For TaskDialogs declared in Xaml, this is automatically set. If you declare a
/// TaskDialog in C#, you MUST set this property before showing the dialog to prevent
/// and error. For desktop platforms, set it to the Window that should own the dialog.
/// For others, set it to the root TopLevel.
/// </remarks>
public IVisual XamlRoot { get; set; }
/// <summary>
/// Raised when the TaskDialog is beginning to open, but is not yet visible
/// </summary>
public event TypedEventHandler<TaskDialog, EventArgs> Opening;
/// <summary>
/// Raised when the TaskDialog is opened and ready to be shown on screen
/// </summary>
public event TypedEventHandler<TaskDialog, EventArgs> Opened;
/// <summary>
/// Raised when the TaskDialog is beginning to close
/// </summary>
public event TypedEventHandler<TaskDialog, TaskDialogClosingEventArgs> Closing;
/// <summary>
/// Raised when the TaskDialog is closed
/// </summary>
public event TypedEventHandler<TaskDialog, EventArgs> Closed;
/// <summary>
/// Shows the TaskDialog
/// </summary>
/// <param name="showHosted">Optional parameter that specifies whether this dialog should show in the OverlayLayer even on windowing platforms. Defaults to false</param>
/// <returns>The TaskDialog result corresponding to the command/button used to close the dialog</returns>
/// <remarks>
/// Before calling this method, you MUST set <see cref="XamlRoot"/> property to the TopLevel/Window that should
/// own or host this Dialog. If you declare the dialog in Xaml, this is done automatically since
/// the dialog is already attached to the visual tree
/// </remarks>
public async Task<object> ShowAsync(bool showHosted = false) { }
/// <summary>
/// Hides the TaskDialog with a <see cref="TaskDialogStandardResult.None"/> result
/// </summary>
public void Hide() { }
/// <summary>
/// Hides the dialog with the specified dialog result
/// </summary>
public void Hide(object result) { }
}
public enum TaskDialogFooterVisibility
{
Never, // Footer is never visible
Auto, // Footer title is visible with expand option to show/hide
Always // Footer is always visible and the footer title is hidden
}
// Base class for controls that can be added to a TaskDialog
// These would be abstractions and not actual controls, TaskDialog would create/manage that
public abstract class TaskDialogControl
{
public TaskDialogControl() { }
public TaskDialogControl(string text, object result) { }
// The text caption of the control
public string Text { get; set; }
// The result the button corresponds to and is returned when the dialog
// closes. Can be TaskDialogStandardResult or an user chosen object
// May not be null
public object DialogResult { get; set; }
// Gets/sets whether the control is enabled
public bool IsEnabled { get; set; }
// Is this the default button - will only be settable on one control
// error thrown if multiple are set
public bool IsDefault { get; set; }
}
// Represents a regular button in a TaskDialog, can be placed in Buttons or
// Options area of dialog
// Buttons placed in the Buttons area will trigger an automatic close of the dialog,
// Buttons placed in the Options area will not, call Hide() if you wish to do so
public class TaskDialogButton : TaskDialogControl
{
public TaskDialogButton() { }
public TaskDialogButton(string text, object result)
:base(text, result) { }
// An optional icon
public IconSource IconSource { get; set; }
/// <summary>
/// Gets or sets the command that is invoked when the button is clicked
/// </summary>
public ICommand Command { get; set; }
/// <summary>
/// Gets or sets the command parameter for the <see cref="Command"/>
/// </summary>
public object CommandParameter { get; set; }
// Event fired when button is clicked/tapped (occurs before dialog close)
public event TypedEventHandler<TaskDialogButton, EventArgs> Click;
// Default Buttons - these will be immutable (no properties / event handlers / commands can be set on them)
public static readonly TaskDialogButton OKButton = new TaskDialogButton("OK", TaskDialogStandardResult.OK);
public static readonly TaskDialogButton CancelButton = new TaskDialogButton("Cancel", TaskDialogStandardResult.Close);
public static readonly TaskDialogButton YesButton = new TaskDialogButton("Yes", TaskDialogStandardResult.Yes);
public static readonly TaskDialogButton NoButton = new TaskDialogButton("No", TaskDialogStandardResult.No);
public static readonly TaskDialogButton RetryButton = new TaskDialogButton("Retry", TaskDialogStandardResult.Retry);
public static readonly TaskDialogButton CloseButton = new TaskDialogButton("Close", TaskDialogStandardResult.Close);
}
// Set of standard results you can use
public enum TaskDialogStandardResult
{
None,
OK,
Cancel,
Yes,
No,
Retry,
Close
}
// Represents a extra options command - can only be placed in the options area
public class TaskDialogCommand : TaskDialogButton
{
// Additional caption for this command button
public string Description { get; set; }
/// <summary>
/// Gets or sets whether invoking this command should also close the dialog
/// </summary>
public bool ClosesOnInvoked { get; set; }
}
// Represents an radiobutton within a TaskDialog - can only be placed in options area
public class TaskDialogRadioButton : TaskDialogCommand
{
public bool? IsChecked { get; set; }
}
public class TaskDialogCheckBox : TaskDialogRadioButton
{
}
Final design:
Issue Analytics
- State:
- Created 2 years ago
- Reactions:5
- Comments:5 (3 by maintainers)
Looks like Avalonia has a discussion as well: https://github.com/AvaloniaUI/Avalonia/issues/670#issuecomment-767827453
FYI, similar ideas were discussed in WinUI here: https://github.com/microsoft/microsoft-ui-xaml/issues/2313. You might find some inspiration/good-ideas there as well.