SukiDialogHost.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106
  1. using System;
  2. using System.Threading.Tasks;
  3. using Avalonia;
  4. using Avalonia.Controls;
  5. using Avalonia.Controls.Primitives;
  6. using Avalonia.Rendering.Composition;
  7. using SukiUI.Dialogs;
  8. using SukiUI.Helpers;
  9. namespace SukiUI.Controls
  10. {
  11. public class SukiDialogHost : TemplatedControl
  12. {
  13. public static readonly StyledProperty<ISukiDialogManager> ManagerProperty = AvaloniaProperty.Register<SukiDialogHost, ISukiDialogManager>(nameof(Manager));
  14. public ISukiDialogManager Manager
  15. {
  16. get => GetValue(ManagerProperty);
  17. set => SetValue(ManagerProperty, value);
  18. }
  19. public static readonly StyledProperty<object?> DialogProperty = AvaloniaProperty.Register<SukiDialogHost, object?>(nameof(Dialog));
  20. internal object? Dialog
  21. {
  22. get => GetValue(DialogProperty);
  23. set => SetValue(DialogProperty, value);
  24. }
  25. public static readonly StyledProperty<bool> IsDialogOpenProperty = AvaloniaProperty.Register<SukiDialogHost, bool>(nameof(IsDialogOpen));
  26. internal bool IsDialogOpen
  27. {
  28. get => GetValue(IsDialogOpenProperty);
  29. set => SetValue(IsDialogOpenProperty, value);
  30. }
  31. protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
  32. {
  33. base.OnApplyTemplate(e);
  34. if (e.NameScope.Find<Border>("PART_DialogBackground") is { } dialogBackground)
  35. {
  36. dialogBackground.PointerPressed += (_, _) => BackgroundRequestClose();
  37. dialogBackground.Loaded += (_, _) =>
  38. {
  39. var v = ElementComposition.GetElementVisual(dialogBackground);
  40. CompositionAnimationHelper.MakeOpacityAnimated(v, 400);
  41. };
  42. }
  43. }
  44. private void BackgroundRequestClose()
  45. {
  46. if (Dialog is not ISukiDialog { CanDismissWithBackgroundClick: true } sukiDialog) return;
  47. if (!sukiDialog.CanDismissWithBackgroundClick) return;
  48. Manager.TryDismissDialog(sukiDialog);
  49. }
  50. private static void OnManagerPropertyChanged(AvaloniaObject sender,
  51. AvaloniaPropertyChangedEventArgs propChanged)
  52. {
  53. if (sender is not SukiDialogHost host)
  54. throw new NullReferenceException("Dependency object is not of valid type " + nameof(SukiDialogHost));
  55. if (propChanged.OldValue is ISukiDialogManager oldManager)
  56. host.DetachManagerEvents(oldManager);
  57. if (propChanged.NewValue is ISukiDialogManager newManager)
  58. host.AttachManagerEvents(newManager);
  59. }
  60. private void AttachManagerEvents(ISukiDialogManager newManager)
  61. {
  62. newManager.OnDialogShown += ManagerOnDialogShown;
  63. newManager.OnDialogDismissed += ManagerOnDialogDismissed;
  64. }
  65. private void DetachManagerEvents(ISukiDialogManager oldManager)
  66. {
  67. oldManager.OnDialogShown -= ManagerOnDialogShown;
  68. oldManager.OnDialogDismissed -= ManagerOnDialogDismissed;
  69. }
  70. private void ManagerOnDialogShown(object sender, SukiDialogManagerEventArgs args)
  71. {
  72. Dialog = args.Dialog;
  73. IsDialogOpen = true;
  74. }
  75. private void ManagerOnDialogDismissed(object sender, SukiDialogManagerEventArgs args)
  76. {
  77. IsDialogOpen = false;
  78. Task.Delay(500).ContinueWith(_ =>
  79. {
  80. if (Dialog != args.Dialog) return;
  81. Dialog = null;
  82. }, TaskScheduler.FromCurrentSynchronizationContext());
  83. }
  84. static SukiDialogHost()
  85. {
  86. ManagerProperty.Changed.Subscribe(
  87. new Avalonia.Reactive.AnonymousObserver<AvaloniaPropertyChangedEventArgs<ISukiDialogManager>>(x =>
  88. OnManagerPropertyChanged(x.Sender, x)));
  89. }
  90. }
  91. }