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; } } }