using System; using System.Windows; using DTS.Common.Enums; using Prism.Regions; using DTS.Common.Events; using DTS.Common.Interactivity; using Microsoft.Xaml.Behaviors; namespace DTS.Common.Dialogs { /// /// Shows a popup window in response to an being raised. /// public class PopupWindowAction : TriggerAction { private Window _openedNotificationWindow; #region DependecyProperties public enum WindowPositions { CenterOwner, CenterScreen } //public enum ResultEnum //{ // Ok = MessageBoxResult.OK, // Yes = MessageBoxResult.Yes, // No = MessageBoxResult.No, // Cancel = MessageBoxResult.Cancel //} /// /// The content of the child window to display as part of the popup. /// public static readonly DependencyProperty WindowContentProperty = DependencyProperty.Register("WindowContent", typeof(FrameworkElement), typeof(PopupWindowAction), new PropertyMetadata(null)); /// /// The to apply to the popup content. /// public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register("ContentTemplate", typeof(DataTemplate), typeof(PopupWindowAction), new PropertyMetadata(null)); /// /// Determines if the content should be shown in a modal window or not. /// public static readonly DependencyProperty IsModalProperty = DependencyProperty.Register("IsModal", typeof(bool), typeof(PopupWindowAction), new PropertyMetadata(null)); /// /// Determines whether the window is shown centered over associated object or entire screen. /// public static readonly DependencyProperty StartupPositionProperty = DependencyProperty.Register("StartupPosition", typeof(WindowPositions), typeof(PopupWindowAction), new PropertyMetadata(WindowPositions.CenterScreen)); /// /// Determines if the content should be initially shown centered over the View that raised the interaction request or not. /// public static readonly DependencyProperty CenterOverAssociatedObjectProperty = DependencyProperty.Register("CenterOverAssociatedObject", typeof(bool), typeof(PopupWindowAction), new PropertyMetadata(null)); /// /// Determines whether the multiple Notification Windows should be allowed. /// public static readonly DependencyProperty AllowMultipleNotificationWindowsProperty = DependencyProperty.Register("AllowMultipleNotificationWindows", typeof(bool), typeof(PopupWindowAction), new PropertyMetadata(null)); ///// ///// Determines timeout interval in milliseconds (0 = no timeout). ///// //public static readonly DependencyProperty TimeoutIntervalProperty = // DependencyProperty.Register("AutoCancelInterval", typeof(int), typeof(PopupWindowAction), new PropertyMetadata(0)); ///// ///// Determines result if timeout occurs. ///// //public static readonly ResultEnum TimeoutResultProperty = // DependencyProperty.Register("TimeoutResult", typeof(ResultEnum), typeof(PopupWindowAction), new PropertyMetadata(ResultEnum.Cancel)); #endregion #region Getters and Setters /// /// Gets or sets the content of the window. /// public FrameworkElement WindowContent { get => (FrameworkElement)GetValue(WindowContentProperty); set => SetValue(WindowContentProperty, value); } /// /// Gets or sets the content template for the window. /// public DataTemplate ContentTemplate { get => (DataTemplate)GetValue(ContentTemplateProperty); set => SetValue(ContentTemplateProperty, value); } /// /// Gets or sets a value indicating whether the window will be modal or not. /// public bool IsModal { get => (bool)GetValue(IsModalProperty); set => SetValue(IsModalProperty, value); } /// /// Gets or sets a value whether the window is shown centered over associated object, the screen or WindowsDefault. /// public WindowPositions StartupPosition { get => (WindowPositions)GetValue(StartupPositionProperty); set => SetValue(StartupPositionProperty, value); } /// /// Gets or sets a value whether the multiple Notification Windows should be allowed. /// This property can be used for the popup window of type only. /// public bool AllowMultipleNotificationWindows { get => (bool)GetValue(AllowMultipleNotificationWindowsProperty); set => SetValue(AllowMultipleNotificationWindowsProperty, value); } ///// ///// Gets or sets a value indicating number of milliseconds before dialog times out (0 = no timeout). ///// //public int TimeoutInterval //{ // get { return (int)GetValue(TimeoutIntervalProperty); } // set { SetValue(TimeoutIntervalProperty, value); } //} ///// ///// Gets or sets a value indicating number of milliseconds before dialog times out (0 = no timeout). ///// //public ResultEnum TimeoutResult //{ // get { return (ResultEnum)GetValue(TimeoutResultProperty); } // set { SetValue(TimeoutResultProperty, value); } //} #endregion #region PopupWindowAction logic /// /// Displays the child window and collects results for . /// /// The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference. protected override void Invoke(object parameter) { var args = parameter as InteractionRequestedEventArgs; if (args == null) return; // If the WindowContent shouldn't be part of another visual tree. if (WindowContent != null && WindowContent.Parent != null) return; var wrapperWindow = GetWindow((Notification)args.Context); if (wrapperWindow == null) return; var callback = args.Callback; EventHandler handler = null; handler = (o, e) => { wrapperWindow.Closed -= handler; wrapperWindow.Content = null; if (_openedNotificationWindow != null && wrapperWindow is NotificationWindow) _openedNotificationWindow = null; callback(); }; wrapperWindow.Closed += handler; // New way, using StartupPosition enumeration: // if (StartupPosition == WindowPositions.CenterOwner || StartupPosition == WindowPositions.CenterScreen) { SizeChangedEventHandler sizeHandler = null; sizeHandler = (o, e) => { wrapperWindow.SizeChanged -= sizeHandler; if (StartupPosition == WindowPositions.CenterOwner) { var invoker = AssociatedObject; var position = invoker.PointToScreen(new Point(0, 0)); wrapperWindow.Top = position.Y + ((invoker.ActualHeight - wrapperWindow.ActualHeight) / 2); wrapperWindow.Left = position.X + ((invoker.ActualWidth - wrapperWindow.ActualWidth) / 2); } else { wrapperWindow.Top = ((SystemParameters.WorkArea.Height - wrapperWindow.ActualHeight) / 2); wrapperWindow.Left = ((SystemParameters.WorkArea.Width - wrapperWindow.ActualWidth) / 2); } }; wrapperWindow.SizeChanged += sizeHandler; } // Old way, using CenterOverAssociatedObject property: // //if (CenterOverAssociatedObject) //{ // SizeChangedEventHandler sizeHandler = null; // sizeHandler = // (o, e) => // { // wrapperWindow.SizeChanged -= sizeHandler; // FrameworkElement invoker = AssociatedObject; // Point position = invoker.PointToScreen(new Point(0, 0)); // wrapperWindow.Top = position.Y + ((invoker.ActualHeight - wrapperWindow.ActualHeight) / 2); // wrapperWindow.Left = position.X + ((invoker.ActualWidth - wrapperWindow.ActualWidth) / 2); // }; // wrapperWindow.SizeChanged += sizeHandler; //} if (AllowMultipleNotificationWindows == false && wrapperWindow is NotificationWindow) _openedNotificationWindow = wrapperWindow; if (IsModal) { wrapperWindow.ShowDialog(); } else { wrapperWindow.Show(); } } /// /// Checks if the WindowContent or its DataContext implements IPopupWindowActionAware and IRegionManagerAware. /// If so, it sets the corresponding values. /// Also, if WindowContent does not have a RegionManager attached, it creates a new scoped RegionManager for it. /// /// The notification to be set as a DataContext in the HostWindow. /// The HostWindow protected void PrepareContentForWindow(Notification notification, Window wrapperWindow) { if (WindowContent == null) return; // We set the WindowContent as the content of the window. wrapperWindow.Content = WindowContent; var regionManager = WindowContent.GetValue(RegionManager.RegionManagerProperty) as IRegionManager; // If the WindowContent does not have a RegionManager attached we create a new scoped RegionManager for it in order to support regions. if (regionManager == null) { regionManager = new RegionManager(); WindowContent.SetValue(RegionManager.RegionManagerProperty, regionManager); } // If the WindowContent implements IRegionManagerAware we set the new scoped manager as the RegionManager. var regionManagerAwareContent = WindowContent as IRegionManagerAware; if (regionManagerAwareContent != null) { regionManagerAwareContent.RegionManager = regionManager; } // If the WindowContent's DataContext implements IRegionManagerAware we set the new scoped manager as the RegionManager. var regionManagerAwareDataContext = WindowContent.DataContext as IRegionManagerAware; if (regionManagerAwareDataContext != null) { regionManagerAwareDataContext.RegionManager = regionManager; } // If the WindowContent implements IPopupWindowActionAware, we set the corresponding values. var popupAwareContent = WindowContent as IPopupWindowActionAware; if (popupAwareContent != null) { popupAwareContent.HostWindow = wrapperWindow; popupAwareContent.HostNotification = notification; } // If the WindowContent's DataContext implements IPopupWindowActionAware, we set the corresponding values. var popupAwareDataContext = WindowContent.DataContext as IPopupWindowActionAware; if (popupAwareDataContext != null) { popupAwareDataContext.HostWindow = wrapperWindow; popupAwareDataContext.HostNotification = notification; } } #endregion #region Window creation methods /// /// Returns the window to display as part of the trigger action. /// /// The notification to be set as a DataContext in the window. /// protected Window GetWindow(Notification notification) { Window wrapperWindow; if (WindowContent != null) { wrapperWindow = new Window(); // If the WindowContent does not have its own DataContext, it will inherit this one. wrapperWindow.DataContext = notification; wrapperWindow.Title = notification.Title; PrepareContentForWindow(notification, wrapperWindow); } else { wrapperWindow = CreateWindow(notification); } return wrapperWindow; } /// /// When no WindowContent is sent this method is used to create a Notification/Confirmation window to show /// the corresponding or . /// /// The Notification or Confirmation parameter to show. /// protected Window CreateWindow(Notification notification) { Window window = null; if (notification is Confirmation) { window = new ConfirmationWindow { ConfirmationTemplate = ContentTemplate }; } else { var content = notification.Content as NotificationContentEventArgs; if (content == null) return null; var imageUri = GetImageUri(content.Image); window = new NotificationWindow { NotificationTemplate = ContentTemplate, ImageUri = imageUri }; } window.DataContext = notification; return window; } /// /// Gets the for the notification image. /// /// The popup window's symbol. private Uri GetImageUri(PopupWindowImage windowImage) { string image; switch (windowImage) { case PopupWindowImage.Error: image = "error_48.png"; break; case PopupWindowImage.Question: image = "question_48.png"; break; case PopupWindowImage.Warning: image = "warning_48.png"; break; case PopupWindowImage.Information: image = "information_48.png"; break; default: image = "warning_48.png"; break; } return new Uri("pack://application:,,,/" + System.Reflection.Assembly.GetExecutingAssembly() + ";component/Images/" + image, UriKind.RelativeOrAbsolute); } #endregion } }