using BPA.UIControl.Commons.KnownBoxes;
using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Media;
namespace BPA.UIControl
{
///
/// 对话框
///
[TemplatePart(Name = TransitionName, Type = typeof(Transition))]
[TemplatePart(Name = CloseButtonPartName, Type = typeof(Button))]
[TemplatePart(Name = BackgroundBorderPartName, Type = typeof(Border))]
[TemplatePart(Name = ContentPresenterPartName, Type = typeof(ContentPresenter))]
public class DialogContainer : ContentControl
{
///
/// 转换动画名称
///
public const string TransitionName = "Path_Transition";
///
/// 关闭按钮名称
///
public const string CloseButtonPartName = "PART_CloseButton";
///
/// 背景 Border 名称
///
public const string BackgroundBorderPartName = "PART_BackgroundBorder";
///
/// Content 内容名称
///
public const string ContentPresenterPartName = "PART_ContentPresenter";
///
/// 对话框结果路由事件处理
///
///
///
public delegate void DialogResultRoutedEventHandler(object sender, DialogResultRoutedEventArgs e);
///
/// 打开对话框前事件处理
///
public Action BeforeOpenHandler;
///
/// 打开对话框后事件处理
///
public Action AfterCloseHandler;
private Border rootBorder;
private object closeParameter;
private List focusableElements; // Content 内 focusable 元素,用于打开弹窗使其失效
///
/// Initializes a new instance of the class.
///
static DialogContainer()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DialogContainer), new FrameworkPropertyMetadata(typeof(DialogContainer)));
}
///
public override void OnApplyTemplate()
{
base.OnApplyTemplate();
CommandBindings.Add(new CommandBinding(CloseDialogCommand, CloseDialogHandler));
CommandBindings.Add(new CommandBinding(OpenDialogCommand, OpenDialogHandler));
ButtonBase closeButton = GetTemplateChild(CloseButtonPartName) as ButtonBase;
closeButton.Click += (sender, args) =>
{
closeParameter = null;
IsShow = false;
};
rootBorder = GetTemplateChild(BackgroundBorderPartName) as Border;
rootBorder.MouseLeftButtonDown += RootBorder_MouseLeftButtonDown;
if (GetTemplateChild(TransitionName) is Transition transition)
{
transition.Showed += (sender, e) => IsClosed = false;
transition.Closed += Closed;
}
if (GetTemplateChild(ContentPresenterPartName) is ContentPresenter contentPresenter)
{
contentPresenter.PreviewKeyDown += ContentPresenter_PreviewKeyDown;
}
focusableElements = new List();
}
#region 命令
///
/// 关闭对话框命令
///
public static RoutedCommand CloseDialogCommand = new RoutedCommand();
///
/// 打开对话框命令
///
public static RoutedCommand OpenDialogCommand = new RoutedCommand();
///
/// 打开前命令
///
public static readonly DependencyProperty BeforeOpenCommandProperty = DependencyProperty.Register(
"BeforeOpenCommand", typeof(ICommand), typeof(DialogContainer));
///
/// 打开前命令
///
public ICommand BeforeOpenCommand
{
get { return (ICommand)GetValue(BeforeOpenCommandProperty); }
set { SetValue(BeforeOpenCommandProperty, value); }
}
///
/// 关闭后命令
///
public static readonly DependencyProperty AfterCloseCommandProperty = DependencyProperty.Register(
"AfterCloseCommand", typeof(ICommand), typeof(DialogContainer));
///
/// 关闭后命令
///
public ICommand AfterCloseCommand
{
get { return (ICommand)GetValue(AfterCloseCommandProperty); }
set { SetValue(AfterCloseCommandProperty, value); }
}
#endregion 命令
#region 事件
///
/// 打开前事件
///
public static readonly RoutedEvent BeforeOpenEvent = EventManager.RegisterRoutedEvent(
"BeforeOpen", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(DialogContainer));
///
/// 打开前事件
///
public event RoutedEventHandler BeforeOpen
{
add { AddHandler(BeforeOpenEvent, value); }
remove { RemoveHandler(BeforeOpenEvent, value); }
}
///
/// 关闭后事件
///
public static readonly RoutedEvent AfterCloseEvent = EventManager.RegisterRoutedEvent(
"AfterClose", RoutingStrategy.Direct, typeof(DialogResultRoutedEventHandler), typeof(DialogContainer));
///
/// 关闭后事件
///
public event DialogResultRoutedEventHandler AfterClose
{
add { AddHandler(AfterCloseEvent, value); }
remove { RemoveHandler(AfterCloseEvent, value); }
}
#endregion 事件
#region 依赖属性
///
/// 标识
///
public static readonly DependencyProperty IdentifierProperty = DependencyProperty.Register(
"Identifier", typeof(string), typeof(DialogContainer), new PropertyMetadata(default(string), OnIdentifierChanged));
private static void OnIdentifierChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DialogContainer dialog = d as DialogContainer;
string identifier = e.NewValue.ToString();
Dialog.AddDialogContainer(identifier, dialog);
}
///
/// 标识
///
public string Identifier
{
get { return (string)GetValue(IdentifierProperty); }
set { SetValue(IdentifierProperty, value); }
}
///
/// 对话框内容
///
public static readonly DependencyProperty DialogContentProperty = DependencyProperty.Register(
"DialogContent", typeof(object), typeof(DialogContainer), new PropertyMetadata(default(object)));
///
/// 对话框内容
///
public object DialogContent
{
get { return GetValue(DialogContentProperty); }
set { SetValue(DialogContentProperty, value); }
}
///
/// 标题
///
public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
"Title", typeof(string), typeof(DialogContainer), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
///
/// 标题
///
public string Title
{
get { return (string)GetValue(TitleProperty); }
set { SetValue(TitleProperty, value); }
}
///
/// 圆角半径
///
public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
"CornerRadius", typeof(CornerRadius), typeof(DialogContainer), new PropertyMetadata(default(CornerRadius)));
///
/// 圆角半径
///
public CornerRadius CornerRadius
{
get { return (CornerRadius)GetValue(CornerRadiusProperty); }
set { SetValue(CornerRadiusProperty, value); }
}
///
/// 是否显示关闭按钮
///
public static readonly DependencyProperty IsShowCloseButtonProperty = DependencyProperty.Register(
"IsShowCloseButton", typeof(bool), typeof(DialogContainer), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
///
/// 是否显示关闭按钮
///
public bool IsShowCloseButton
{
get { return (bool)GetValue(IsShowCloseButtonProperty); }
set { SetValue(IsShowCloseButtonProperty, BooleanBoxes.Box(value)); }
}
///
/// 是否 esc 键关闭弹窗 (点击空白关闭)
///
public static readonly DependencyProperty IsEscKeyToCloseProperty = DependencyProperty.Register(
"IsEscKeyToClose", typeof(bool), typeof(DialogContainer), new PropertyMetadata(BooleanBoxes.FalseBox, OnIsEscKeyToCloseChanged));
private static void OnIsEscKeyToCloseChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
if (d is DialogContainer dialog)
{
if (dialog.IsEscKeyToClose)
{
var escKeyBinding = new KeyBinding(DialogContainer.CloseDialogCommand, Key.Escape, ModifierKeys.None);
dialog.InputBindings.Add(escKeyBinding);
}
else
{
foreach (var inputBinding in dialog.InputBindings)
{
if (inputBinding is KeyBinding keyBinding && keyBinding.Key == Key.Escape)
{
dialog.InputBindings.Remove(keyBinding);
}
}
}
}
}
///
/// 是否 esc 键关闭弹窗 (点击空白关闭)
///
public bool IsEscKeyToClose
{
get { return (bool)GetValue(IsEscKeyToCloseProperty); }
set { SetValue(IsEscKeyToCloseProperty, BooleanBoxes.Box(value)); }
}
///
/// 是否显示
///
public static readonly DependencyProperty IsShowProperty = DependencyProperty.Register(
"IsShow", typeof(bool), typeof(DialogContainer), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, OnIsShowChanged));
private static void OnIsShowChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
DialogContainer dialog = d as DialogContainer;
if (dialog.IsShow)
{
if (dialog.Content is FrameworkElement dialogContent)
{
dialogContent.ForEachVisualChild(x =>
{
if (x is FrameworkElement element && element.Focusable)
{
element.Focusable = false;
dialog.focusableElements.Add(element);
}
});
dialog.OpenAnimiation(dialog);
}
}
else
{
dialog.focusableElements.ForEach(x => x.Focusable = true);
dialog.focusableElements.Clear();
}
}
///
/// 是否显示
///
public bool IsShow
{
get { return (bool)GetValue(IsShowProperty); }
set { SetValue(IsShowProperty, BooleanBoxes.Box(value)); }
}
///
/// 遮罩背景色
///
public static readonly DependencyProperty MaskBackgroundProperty = DependencyProperty.Register(
"MaskBackground", typeof(Brush), typeof(DialogContainer), new PropertyMetadata(default(Brush)));
///
/// 遮罩背景色
///
public Brush MaskBackground
{
get { return (Brush)GetValue(MaskBackgroundProperty); }
set { SetValue(MaskBackgroundProperty, value); }
}
///
/// 关闭完成
///
public static readonly DependencyProperty IsClosedProperty = DependencyProperty.Register(
"IsClosed", typeof(bool), typeof(DialogContainer), new PropertyMetadata(BooleanBoxes.FalseBox));
///
/// 关闭完成
///
public bool IsClosed
{
get { return (bool)GetValue(IsClosedProperty); }
set { SetValue(IsClosedProperty, BooleanBoxes.Box(value)); }
}
#endregion 依赖属性
private void OpenDialogHandler(object sender, ExecutedRoutedEventArgs e)
{
IsShow = true;
}
private void CloseDialogHandler(object sender, ExecutedRoutedEventArgs e)
{
closeParameter = e.Parameter;
IsShow = false;
}
private void RootBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
if (e.OriginalSource is Border border)
{
if (IsEscKeyToClose && sender.Equals(border))
{
closeParameter = null;
IsShow = false;
}
}
}
///
/// 关闭对话框
///
/// 参数
public void Close(object parameter = null)
{
CloseDialogCommand.Execute(parameter, this);
}
// 打开对话框动作
private void OpenAnimiation(DialogContainer dialog)
{
RoutedEventArgs args = new RoutedEventArgs(BeforeOpenEvent);
dialog.RaiseEvent(args);
dialog.BeforeOpenCommand?.Execute(null);
dialog.BeforeOpenHandler?.Invoke(dialog);
_ = dialog.Focus();
}
private void Closed(object sender, RoutedEventArgs e)
{
IsClosed = true;
var args = new DialogResultRoutedEventArgs(AfterCloseEvent, this.closeParameter, this);
args.RoutedEvent = AfterCloseEvent;
this.RaiseEvent(args);
this.AfterCloseCommand?.Execute(this.closeParameter);
this.AfterCloseHandler?.Invoke(this, this.closeParameter);
this.closeParameter = null;
this.BeforeOpenHandler = null;
this.AfterCloseHandler = null;
}
private void ContentPresenter_PreviewKeyDown(object sender, KeyEventArgs e)
{
Key key = e.Key == Key.System ? e.SystemKey : e.Key;
if (key == Key.Tab && IsShow)
{
e.Handled = true;
}
}
}
///
/// 对话框结果路由参数
///
public class DialogResultRoutedEventArgs : RoutedEventArgs
{
///
/// 结果
///
public object Result { get; set; }
///
/// 对话框
///
public DialogContainer Dialog { get; set; }
///
/// Initializes a new instance of the class.
///
/// The routed event.
/// The result.
/// The dialog.
public DialogResultRoutedEventArgs(RoutedEvent routedEvent, object result, DialogContainer dialog)
: base(routedEvent)
{
Result = result;
Dialog = dialog;
}
}
}