using System.Windows.Controls;
using WPFluent.Input;
// ReSharper disable once CheckNamespace
namespace WPFluent.Controls;
///
/// Dialogue displayed inside the application covering its internals, displaying some content.
///
///
///
/// <ContentPresenter x:Name="RootContentDialogPresenter" Grid.Row="0" />
///
///
/// var contentDialog = new ContentDialog(RootContentDialogPresenter);
///
/// contentDialog.SetCurrentValue(ContentDialog.TitleProperty, "Hello World");
/// contentDialog.SetCurrentValue(ContentControl.ContentProperty, "This is a message");
/// contentDialog.SetCurrentValue(ContentDialog.CloseButtonTextProperty, "Close this dialog");
///
/// await contentDialog.ShowAsync(cancellationToken);
///
///
/// var contentDialogService = new ContentDialogService();
/// contentDialogService.SetContentPresenter(RootContentDialogPresenter);
///
/// await _contentDialogService.ShowSimpleDialogAsync(
/// new SimpleContentDialogCreateOptions()
/// {
/// Title = "The cake?",
/// Content = "IS A LIE!",
/// PrimaryButtonText = "Save",
/// SecondaryButtonText = "Don't Save",
/// CloseButtonText = "Cancel"
/// }
/// );
///
///
public class ContentDialog : ContentControl
{
/// Identifies the dependency property.
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
nameof(Title),
typeof(object),
typeof(ContentDialog),
new PropertyMetadata(null)
);
/// Identifies the dependency property.
public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register(
nameof(TitleTemplate),
typeof(DataTemplate),
typeof(ContentDialog),
new PropertyMetadata(null)
);
/// Identifies the dependency property.
public static readonly DependencyProperty DialogWidthProperty = DependencyProperty.Register(
nameof(DialogWidth),
typeof(double),
typeof(ContentDialog),
new PropertyMetadata(double.PositiveInfinity)
);
/// Identifies the dependency property.
public static readonly DependencyProperty DialogHeightProperty = DependencyProperty.Register(
nameof(DialogHeight),
typeof(double),
typeof(ContentDialog),
new PropertyMetadata(double.PositiveInfinity)
);
/// Identifies the dependency property.
public static readonly DependencyProperty DialogMaxWidthProperty = DependencyProperty.Register(
nameof(DialogMaxWidth),
typeof(double),
typeof(ContentDialog),
new PropertyMetadata(double.PositiveInfinity)
);
/// Identifies the dependency property.
public static readonly DependencyProperty DialogMaxHeightProperty = DependencyProperty.Register(
nameof(DialogMaxHeight),
typeof(double),
typeof(ContentDialog),
new PropertyMetadata(double.PositiveInfinity)
);
/// Identifies the dependency property.
public static readonly DependencyProperty DialogMarginProperty = DependencyProperty.Register(
nameof(DialogMargin),
typeof(Thickness),
typeof(ContentDialog)
);
/// Identifies the dependency property.
public static readonly DependencyProperty PrimaryButtonTextProperty = DependencyProperty.Register(
nameof(PrimaryButtonText),
typeof(string),
typeof(ContentDialog),
new PropertyMetadata(string.Empty)
);
/// Identifies the dependency property.
public static readonly DependencyProperty SecondaryButtonTextProperty = DependencyProperty.Register(
nameof(SecondaryButtonText),
typeof(string),
typeof(ContentDialog),
new PropertyMetadata(string.Empty)
);
/// Identifies the dependency property.
public static readonly DependencyProperty CloseButtonTextProperty = DependencyProperty.Register(
nameof(CloseButtonText),
typeof(string),
typeof(ContentDialog),
new PropertyMetadata("Close")
);
/// Identifies the dependency property.
public static readonly DependencyProperty PrimaryButtonIconProperty = DependencyProperty.Register(
nameof(PrimaryButtonIcon),
typeof(IconElement),
typeof(ContentDialog),
new PropertyMetadata(null)
);
/// Identifies the dependency property.
public static readonly DependencyProperty SecondaryButtonIconProperty = DependencyProperty.Register(
nameof(SecondaryButtonIcon),
typeof(IconElement),
typeof(ContentDialog),
new PropertyMetadata(null)
);
/// Identifies the dependency property.
public static readonly DependencyProperty CloseButtonIconProperty = DependencyProperty.Register(
nameof(CloseButtonIcon),
typeof(IconElement),
typeof(ContentDialog),
new PropertyMetadata(null)
);
/// Identifies the dependency property.
public static readonly DependencyProperty IsPrimaryButtonEnabledProperty = DependencyProperty.Register(
nameof(IsPrimaryButtonEnabled),
typeof(bool),
typeof(ContentDialog),
new PropertyMetadata(true)
);
/// Identifies the dependency property.
public static readonly DependencyProperty IsPrimaryButtonAvailableProperty = DependencyProperty.Register(
nameof(IsPrimaryButtonAvailable),
typeof(bool),
typeof(ContentDialog),
new PropertyMetadata(true)
);
/// Identifies the dependency property.
public static readonly DependencyProperty IsSecondaryButtonEnabledProperty = DependencyProperty.Register(
nameof(IsSecondaryButtonEnabled),
typeof(bool),
typeof(ContentDialog),
new PropertyMetadata(true)
);
/// Identifies the dependency property.
public static readonly DependencyProperty PrimaryButtonAppearanceProperty = DependencyProperty.Register(
nameof(PrimaryButtonAppearance),
typeof(ControlAppearance),
typeof(ContentDialog),
new PropertyMetadata(ControlAppearance.Primary)
);
/// Identifies the dependency property.
public static readonly DependencyProperty SecondaryButtonAppearanceProperty = DependencyProperty.Register(
nameof(SecondaryButtonAppearance),
typeof(ControlAppearance),
typeof(ContentDialog),
new PropertyMetadata(ControlAppearance.Secondary)
);
/// Identifies the dependency property.
public static readonly DependencyProperty CloseButtonAppearanceProperty = DependencyProperty.Register(
nameof(CloseButtonAppearance),
typeof(ControlAppearance),
typeof(ContentDialog),
new PropertyMetadata(ControlAppearance.Secondary)
);
/// Identifies the dependency property.
public static readonly DependencyProperty DefaultButtonProperty = DependencyProperty.Register(
nameof(DefaultButton),
typeof(ContentDialogButton),
typeof(ContentDialog),
new PropertyMetadata(ContentDialogButton.Primary)
);
/// Identifies the dependency property.
public static readonly DependencyProperty IsFooterVisibleProperty = DependencyProperty.Register(
nameof(IsFooterVisible),
typeof(bool),
typeof(ContentDialog),
new PropertyMetadata(true)
);
/// Identifies the dependency property.
public static readonly DependencyProperty TemplateButtonCommandProperty = DependencyProperty.Register(
nameof(TemplateButtonCommand),
typeof(IRelayCommand),
typeof(ContentDialog),
new PropertyMetadata(null)
);
/// Identifies the routed event.
public static readonly RoutedEvent OpenedEvent = EventManager.RegisterRoutedEvent(
nameof(Opened),
RoutingStrategy.Bubble,
typeof(TypedEventHandler),
typeof(ContentDialog)
);
/// Identifies the routed event.
public static readonly RoutedEvent ClosingEvent = EventManager.RegisterRoutedEvent(
nameof(Closing),
RoutingStrategy.Bubble,
typeof(TypedEventHandler),
typeof(ContentDialog)
);
/// Identifies the routed event.
public static readonly RoutedEvent ClosedEvent = EventManager.RegisterRoutedEvent(
nameof(Closed),
RoutingStrategy.Bubble,
typeof(TypedEventHandler),
typeof(ContentDialog)
);
/// Identifies the routed event.
public static readonly RoutedEvent ButtonClickedEvent = EventManager.RegisterRoutedEvent(
nameof(ButtonClicked),
RoutingStrategy.Bubble,
typeof(TypedEventHandler),
typeof(ContentDialog)
);
///
/// Gets or sets the title of the .
///
public object? Title
{
get => GetValue(TitleProperty);
set => SetValue(TitleProperty, value);
}
///
/// Gets or sets the title template of the .
///
public DataTemplate? TitleTemplate
{
get => (DataTemplate?)GetValue(TitleTemplateProperty);
set => SetValue(TitleTemplateProperty, value);
}
///
/// Gets or sets the width of the .
///
public double DialogWidth
{
get => (double)GetValue(DialogWidthProperty);
set => SetValue(DialogWidthProperty, value);
}
///
/// Gets or sets the height of the .
///
public double DialogHeight
{
get => (double)GetValue(DialogHeightProperty);
set => SetValue(DialogHeightProperty, value);
}
///
/// Gets or sets the max width of the .
///
public double DialogMaxWidth
{
get => (double)GetValue(DialogMaxWidthProperty);
set => SetValue(DialogMaxWidthProperty, value);
}
///
/// Gets or sets the max height of the .
///
public double DialogMaxHeight
{
get => (double)GetValue(DialogMaxHeightProperty);
set => SetValue(DialogMaxHeightProperty, value);
}
///
/// Gets or sets the margin of the .
///
public Thickness DialogMargin
{
get => (Thickness)GetValue(DialogMarginProperty);
set => SetValue(DialogMarginProperty, value);
}
///
/// Gets or sets the text to display on the primary button.
///
public string PrimaryButtonText
{
get => (string)GetValue(PrimaryButtonTextProperty);
set => SetValue(PrimaryButtonTextProperty, value);
}
///
/// Gets or sets the text to be displayed on the secondary button.
///
public string SecondaryButtonText
{
get => (string)GetValue(SecondaryButtonTextProperty);
set => SetValue(SecondaryButtonTextProperty, value);
}
///
/// Gets or sets the text to display on the close button.
///
public string CloseButtonText
{
get => (string)GetValue(CloseButtonTextProperty);
set => SetValue(CloseButtonTextProperty, value);
}
///
/// Gets or sets the on the secondary button.
///
public IconElement? PrimaryButtonIcon
{
get => (IconElement?)GetValue(PrimaryButtonIconProperty);
set => SetValue(PrimaryButtonIconProperty, value);
}
///
/// Gets or sets the on the primary button.
///
public IconElement? SecondaryButtonIcon
{
get => (IconElement?)GetValue(SecondaryButtonIconProperty);
set => SetValue(SecondaryButtonIconProperty, value);
}
///
/// Gets or sets the on the close button.
///
public IconElement? CloseButtonIcon
{
get => (IconElement?)GetValue(CloseButtonIconProperty);
set => SetValue(CloseButtonIconProperty, value);
}
///
/// Gets or sets a value indicating whether the primary button is enabled.
///
public bool IsPrimaryButtonEnabled
{
get => (bool)GetValue(IsPrimaryButtonEnabledProperty);
set => SetValue(IsPrimaryButtonEnabledProperty, value);
}
///
/// Gets or sets a value indicating whether the primary button is available.
///
public bool IsPrimaryButtonAvailable
{
get => (bool)GetValue(IsPrimaryButtonAvailableProperty);
set => SetValue(IsPrimaryButtonAvailableProperty, value);
}
///
/// Gets or sets a value indicating whether the secondary button is enabled.
///
public bool IsSecondaryButtonEnabled
{
get => (bool)GetValue(IsSecondaryButtonEnabledProperty);
set => SetValue(IsSecondaryButtonEnabledProperty, value);
}
///
/// Gets or sets the to apply to the primary button.
///
public ControlAppearance PrimaryButtonAppearance
{
get => (ControlAppearance)GetValue(PrimaryButtonAppearanceProperty);
set => SetValue(PrimaryButtonAppearanceProperty, value);
}
///
/// Gets or sets the to apply to the secondary button.
///
public ControlAppearance SecondaryButtonAppearance
{
get => (ControlAppearance)GetValue(SecondaryButtonAppearanceProperty);
set => SetValue(SecondaryButtonAppearanceProperty, value);
}
///
/// Gets or sets the to apply to the close button.
///
public ControlAppearance CloseButtonAppearance
{
get => (ControlAppearance)GetValue(CloseButtonAppearanceProperty);
set => SetValue(CloseButtonAppearanceProperty, value);
}
///
/// Gets or sets a value that indicates which button on the dialog is the default action.
///
public ContentDialogButton DefaultButton
{
get => (ContentDialogButton)GetValue(DefaultButtonProperty);
set => SetValue(DefaultButtonProperty, value);
}
///
/// Gets or sets a value indicating whether the footer buttons are visible.
///
public bool IsFooterVisible
{
get => (bool)GetValue(IsFooterVisibleProperty);
set => SetValue(IsFooterVisibleProperty, value);
}
///
/// Gets command triggered after clicking the button in the template.
///
internal IRelayCommand TemplateButtonCommand => (IRelayCommand)GetValue(TemplateButtonCommandProperty);
///
/// Occurs after the dialog is opened.
///
public event TypedEventHandler Opened
{
add => AddHandler(OpenedEvent, value);
remove => RemoveHandler(OpenedEvent, value);
}
///
/// Occurs after the dialog starts to close, but before it is closed and before the event occurs.
///
public event TypedEventHandler Closing
{
add => AddHandler(ClosingEvent, value);
remove => RemoveHandler(ClosingEvent, value);
}
///
/// Occurs after the dialog is closed.
///
public event TypedEventHandler Closed
{
add => AddHandler(ClosedEvent, value);
remove => RemoveHandler(ClosedEvent, value);
}
///
/// Occurs after the has been tapped.
///
public event TypedEventHandler ButtonClicked
{
add => AddHandler(ButtonClickedEvent, value);
remove => RemoveHandler(ButtonClickedEvent, value);
}
///
/// Initializes a new instance of the class.
///
public ContentDialog()
{
SetValue(TemplateButtonCommandProperty, new RelayCommand(OnButtonClick));
Loaded += static (sender, _) =>
{
var self = (ContentDialog)sender;
self.OnLoaded();
};
}
///
/// Initializes a new instance of the class.
///
/// inside of which the dialogue will be placed. The new will replace the current .
public ContentDialog(ContentPresenter? dialogHost)
{
if (dialogHost is null)
{
throw new ArgumentNullException(nameof(dialogHost));
}
DialogHost = dialogHost;
SetValue(TemplateButtonCommandProperty, new RelayCommand(OnButtonClick));
Loaded += static (sender, _) =>
{
var self = (ContentDialog)sender;
self.OnLoaded();
};
}
///
/// Gets or sets inside of which the dialogue will be placed. The new will replace the current .
///
public ContentPresenter? DialogHost { get; set; } = default;
protected TaskCompletionSource? Tcs { get; set; }
///
/// Shows the dialog
///
[System.Diagnostics.CodeAnalysis.SuppressMessage(
"WpfAnalyzers.DependencyProperty",
"WPF0041:Set mutable dependency properties using SetCurrentValue",
Justification = "SetCurrentValue(ContentProperty, ...) will not work"
)]
public async Task ShowAsync(CancellationToken cancellationToken = default)
{
if (DialogHost is null)
{
throw new InvalidOperationException("DialogHost was not set");
}
Tcs = new TaskCompletionSource();
CancellationTokenRegistration tokenRegistration = cancellationToken.Register(
o => Tcs.TrySetCanceled((CancellationToken)o!),
cancellationToken
);
ContentDialogResult result = ContentDialogResult.None;
try
{
DialogHost.Content = this;
result = await Tcs.Task;
return result;
}
finally
{
#if NET6_0_OR_GREATER
await tokenRegistration.DisposeAsync();
#else
tokenRegistration.Dispose();
#endif
DialogHost.Content = null;
OnClosed(result);
}
}
///
/// Hides the dialog with result
///
public virtual void Hide(ContentDialogResult result = ContentDialogResult.None)
{
var closingEventArgs = new ContentDialogClosingEventArgs(ClosingEvent, this) { Result = result };
RaiseEvent(closingEventArgs);
if (!closingEventArgs.Cancel)
{
Tcs?.TrySetResult(result);
}
}
///
/// Occurs after ContentPresenter.Content = null
///
protected virtual void OnClosed(ContentDialogResult result)
{
var closedEventArgs = new ContentDialogClosedEventArgs(ClosedEvent, this) { Result = result };
RaiseEvent(closedEventArgs);
}
///
/// Invoked when a is clicked.
///
/// The button that was clicked.
protected virtual void OnButtonClick(ContentDialogButton button)
{
var buttonClickEventArgs = new ContentDialogButtonClickEventArgs(ButtonClickedEvent, this)
{
Button = button,
};
RaiseEvent(buttonClickEventArgs);
ContentDialogResult result = button switch
{
ContentDialogButton.Primary => ContentDialogResult.Primary,
ContentDialogButton.Secondary => ContentDialogResult.Secondary,
_ => ContentDialogResult.None,
};
Hide(result);
}
// protected override Size MeasureOverride(Size availableSize)
// {
// var rootElement = (UIElement)GetVisualChild(0)!;
//
// rootElement.Measure(availableSize);
// Size desiredSize = rootElement.DesiredSize;
//
// Size newSize = GetNewDialogSize(desiredSize);
//
// SetCurrentValue(DialogHeightProperty, newSize.Height);
// SetCurrentValue(DialogWidthProperty, newSize.Width);
//
// ResizeWidth(rootElement);
// ResizeHeight(rootElement);
//
// return desiredSize;
// }
///
/// Occurs after Loaded event
///
protected virtual void OnLoaded()
{
Focus();
RaiseEvent(new RoutedEventArgs(OpenedEvent));
}
// private Size GetNewDialogSize(Size desiredSize)
// {
// // TODO: Handle negative values
// var paddingWidth = Padding.Left + Padding.Right;
// var paddingHeight = Padding.Top + Padding.Bottom;
//
// var marginHeight = DialogMargin.Bottom + DialogMargin.Top;
// var marginWidth = DialogMargin.Left + DialogMargin.Right;
//
// var width = desiredSize.Width - marginWidth + paddingWidth;
// var height = desiredSize.Height - marginHeight + paddingHeight;
//
// return new Size(width, height);
// }
// private void ResizeWidth(UIElement element)
// {
// if (DialogWidth <= DialogMaxWidth)
// {
// return;
// }
//
// SetCurrentValue(DialogWidthProperty, DialogMaxWidth);
// element.UpdateLayout();
//
// SetCurrentValue(DialogHeightProperty, element.DesiredSize.Height);
//
// if (DialogHeight > DialogMaxHeight)
// {
// SetCurrentValue(DialogMaxHeightProperty, DialogHeight);
// /*Debug.WriteLine($"DEBUG | {GetType()} | WARNING | DialogHeight > DialogMaxHeight after resizing width!");*/
// }
// }
// private void ResizeHeight(UIElement element)
// {
// if (DialogHeight <= DialogMaxHeight)
// {
// return;
// }
//
// SetCurrentValue(DialogHeightProperty, DialogMaxHeight);
// element.UpdateLayout();
//
// SetCurrentValue(DialogWidthProperty, element.DesiredSize.Width);
//
// if (DialogWidth > DialogMaxWidth)
// {
// SetCurrentValue(DialogMaxWidthProperty, DialogWidth);
// /*Debug.WriteLine($"DEBUG | {GetType()} | WARNING | DialogWidth > DialogMaxWidth after resizing height!");*/
// }
// }
}