|
- 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
- {
- /// <summary>
- /// 对话框
- /// </summary>
- [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
- {
- /// <summary>
- /// 转换动画名称
- /// </summary>
- public const string TransitionName = "Path_Transition";
-
- /// <summary>
- /// 关闭按钮名称
- /// </summary>
- public const string CloseButtonPartName = "PART_CloseButton";
-
- /// <summary>
- /// 背景 Border 名称
- /// </summary>
- public const string BackgroundBorderPartName = "PART_BackgroundBorder";
-
- /// <summary>
- /// Content 内容名称
- /// </summary>
- public const string ContentPresenterPartName = "PART_ContentPresenter";
-
- /// <summary>
- /// 对话框结果路由事件处理
- /// </summary>
- /// <param name="sender"></param>
- /// <param name="e"></param>
- public delegate void DialogResultRoutedEventHandler(object sender, DialogResultRoutedEventArgs e);
-
- /// <summary>
- /// 打开对话框前事件处理
- /// </summary>
- public Action<DialogContainer> BeforeOpenHandler;
-
- /// <summary>
- /// 打开对话框后事件处理
- /// </summary>
- public Action<DialogContainer, object> AfterCloseHandler;
-
- private Border rootBorder;
- private object closeParameter;
- private List<FrameworkElement> focusableElements; // Content 内 focusable 元素,用于打开弹窗使其失效
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DialogContainer"/> class.
- /// </summary>
- static DialogContainer()
- {
- DefaultStyleKeyProperty.OverrideMetadata(typeof(DialogContainer), new FrameworkPropertyMetadata(typeof(DialogContainer)));
- }
-
- /// <inheritdoc/>
- 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<FrameworkElement>();
- }
-
- #region 命令
-
- /// <summary>
- /// 关闭对话框命令
- /// </summary>
- public static RoutedCommand CloseDialogCommand = new RoutedCommand();
-
- /// <summary>
- /// 打开对话框命令
- /// </summary>
- public static RoutedCommand OpenDialogCommand = new RoutedCommand();
-
- /// <summary>
- /// 打开前命令
- /// </summary>
- public static readonly DependencyProperty BeforeOpenCommandProperty = DependencyProperty.Register(
- "BeforeOpenCommand", typeof(ICommand), typeof(DialogContainer));
-
- /// <summary>
- /// 打开前命令
- /// </summary>
- public ICommand BeforeOpenCommand
- {
- get { return (ICommand)GetValue(BeforeOpenCommandProperty); }
- set { SetValue(BeforeOpenCommandProperty, value); }
- }
-
- /// <summary>
- /// 关闭后命令
- /// </summary>
- public static readonly DependencyProperty AfterCloseCommandProperty = DependencyProperty.Register(
- "AfterCloseCommand", typeof(ICommand), typeof(DialogContainer));
-
- /// <summary>
- /// 关闭后命令
- /// </summary>
- public ICommand AfterCloseCommand
- {
- get { return (ICommand)GetValue(AfterCloseCommandProperty); }
- set { SetValue(AfterCloseCommandProperty, value); }
- }
-
- #endregion 命令
-
- #region 事件
-
- /// <summary>
- /// 打开前事件
- /// </summary>
- public static readonly RoutedEvent BeforeOpenEvent = EventManager.RegisterRoutedEvent(
- "BeforeOpen", RoutingStrategy.Direct, typeof(RoutedEventHandler), typeof(DialogContainer));
-
- /// <summary>
- /// 打开前事件
- /// </summary>
- public event RoutedEventHandler BeforeOpen
- {
- add { AddHandler(BeforeOpenEvent, value); }
- remove { RemoveHandler(BeforeOpenEvent, value); }
- }
-
- /// <summary>
- /// 关闭后事件
- /// </summary>
- public static readonly RoutedEvent AfterCloseEvent = EventManager.RegisterRoutedEvent(
- "AfterClose", RoutingStrategy.Direct, typeof(DialogResultRoutedEventHandler), typeof(DialogContainer));
-
- /// <summary>
- /// 关闭后事件
- /// </summary>
- public event DialogResultRoutedEventHandler AfterClose
- {
- add { AddHandler(AfterCloseEvent, value); }
- remove { RemoveHandler(AfterCloseEvent, value); }
- }
-
- #endregion 事件
-
- #region 依赖属性
-
- /// <summary>
- /// 标识
- /// </summary>
- 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);
- }
-
- /// <summary>
- /// 标识
- /// </summary>
- public string Identifier
- {
- get { return (string)GetValue(IdentifierProperty); }
- set { SetValue(IdentifierProperty, value); }
- }
-
- /// <summary>
- /// 对话框内容
- /// </summary>
- public static readonly DependencyProperty DialogContentProperty = DependencyProperty.Register(
- "DialogContent", typeof(object), typeof(DialogContainer), new PropertyMetadata(default(object)));
-
- /// <summary>
- /// 对话框内容
- /// </summary>
- public object DialogContent
- {
- get { return GetValue(DialogContentProperty); }
- set { SetValue(DialogContentProperty, value); }
- }
-
- /// <summary>
- /// 标题
- /// </summary>
- public static readonly DependencyProperty TitleProperty = DependencyProperty.Register(
- "Title", typeof(string), typeof(DialogContainer), new FrameworkPropertyMetadata(default(string), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
-
- /// <summary>
- /// 标题
- /// </summary>
- public string Title
- {
- get { return (string)GetValue(TitleProperty); }
- set { SetValue(TitleProperty, value); }
- }
-
- /// <summary>
- /// 圆角半径
- /// </summary>
- public static readonly DependencyProperty CornerRadiusProperty = DependencyProperty.Register(
- "CornerRadius", typeof(CornerRadius), typeof(DialogContainer), new PropertyMetadata(default(CornerRadius)));
-
- /// <summary>
- /// 圆角半径
- /// </summary>
- public CornerRadius CornerRadius
- {
- get { return (CornerRadius)GetValue(CornerRadiusProperty); }
- set { SetValue(CornerRadiusProperty, value); }
- }
-
- /// <summary>
- /// 是否显示关闭按钮
- /// </summary>
- public static readonly DependencyProperty IsShowCloseButtonProperty = DependencyProperty.Register(
- "IsShowCloseButton", typeof(bool), typeof(DialogContainer), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault));
-
- /// <summary>
- /// 是否显示关闭按钮
- /// </summary>
- public bool IsShowCloseButton
- {
- get { return (bool)GetValue(IsShowCloseButtonProperty); }
- set { SetValue(IsShowCloseButtonProperty, BooleanBoxes.Box(value)); }
- }
-
- /// <summary>
- /// 是否 esc 键关闭弹窗 (点击空白关闭)
- /// </summary>
- 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);
- }
- }
- }
- }
- }
-
- /// <summary>
- /// 是否 esc 键关闭弹窗 (点击空白关闭)
- /// </summary>
- public bool IsEscKeyToClose
- {
- get { return (bool)GetValue(IsEscKeyToCloseProperty); }
- set { SetValue(IsEscKeyToCloseProperty, BooleanBoxes.Box(value)); }
- }
-
- /// <summary>
- /// 是否显示
- /// </summary>
- 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();
- }
- }
-
- /// <summary>
- /// 是否显示
- /// </summary>
- public bool IsShow
- {
- get { return (bool)GetValue(IsShowProperty); }
- set { SetValue(IsShowProperty, BooleanBoxes.Box(value)); }
- }
-
- /// <summary>
- /// 遮罩背景色
- /// </summary>
- public static readonly DependencyProperty MaskBackgroundProperty = DependencyProperty.Register(
- "MaskBackground", typeof(Brush), typeof(DialogContainer), new PropertyMetadata(default(Brush)));
-
- /// <summary>
- /// 遮罩背景色
- /// </summary>
- public Brush MaskBackground
- {
- get { return (Brush)GetValue(MaskBackgroundProperty); }
- set { SetValue(MaskBackgroundProperty, value); }
- }
-
- /// <summary>
- /// 关闭完成
- /// </summary>
- public static readonly DependencyProperty IsClosedProperty = DependencyProperty.Register(
- "IsClosed", typeof(bool), typeof(DialogContainer), new PropertyMetadata(BooleanBoxes.FalseBox));
-
- /// <summary>
- /// 关闭完成
- /// </summary>
- 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;
- }
- }
- }
-
- /// <summary>
- /// 关闭对话框
- /// </summary>
- /// <param name="parameter">参数</param>
- 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;
- }
- }
- }
-
- /// <summary>
- /// 对话框结果路由参数
- /// </summary>
- public class DialogResultRoutedEventArgs : RoutedEventArgs
- {
- /// <summary>
- /// 结果
- /// </summary>
- public object Result { get; set; }
-
- /// <summary>
- /// 对话框
- /// </summary>
- public DialogContainer Dialog { get; set; }
-
- /// <summary>
- /// Initializes a new instance of the <see cref="DialogResultRoutedEventArgs"/> class.
- /// </summary>
- /// <param name="routedEvent">The routed event.</param>
- /// <param name="result">The result.</param>
- /// <param name="dialog">The dialog.</param>
- public DialogResultRoutedEventArgs(RoutedEvent routedEvent, object result, DialogContainer dialog)
- : base(routedEvent)
- {
- Result = result;
- Dialog = dialog;
- }
- }
- }
|