Files
DP44/Common/DTS.CommonCore/Dialogs/PopupWindowAction.cs
2026-04-17 14:55:32 -04:00

399 lines
16 KiB
C#

using System;
using System.Windows;
using System.Windows.Interactivity;
using DTS.Common.Enums;
using Microsoft.Practices.Prism.Interactivity.InteractionRequest;
using Microsoft.Practices.Prism.Regions;
using DTS.Common.Events;
namespace DTS.Common.Dialogs
{
/// <summary>
/// Shows a popup window in response to an <see cref="Microsoft.Practices.Prism.Interactivity.InteractionRequest"/> being raised.
/// </summary>
public class PopupWindowAction : TriggerAction<FrameworkElement>
{
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
//}
/// <summary>
/// The content of the child window to display as part of the popup.
/// </summary>
public static readonly DependencyProperty WindowContentProperty =
DependencyProperty.Register("WindowContent", typeof(FrameworkElement), typeof(PopupWindowAction), new PropertyMetadata(null));
/// <summary>
/// The <see cref="DataTemplate"/> to apply to the popup content.
/// </summary>
public static readonly DependencyProperty ContentTemplateProperty =
DependencyProperty.Register("ContentTemplate", typeof(DataTemplate), typeof(PopupWindowAction), new PropertyMetadata(null));
/// <summary>
/// Determines if the content should be shown in a modal window or not.
/// </summary>
public static readonly DependencyProperty IsModalProperty =
DependencyProperty.Register("IsModal", typeof(bool), typeof(PopupWindowAction), new PropertyMetadata(null));
/// <summary>
/// Determines whether the window is shown centered over associated object or entire screen.
/// </summary>
public static readonly DependencyProperty StartupPositionProperty =
DependencyProperty.Register("StartupPosition", typeof(WindowPositions), typeof(PopupWindowAction), new PropertyMetadata(WindowPositions.CenterScreen));
/// <summary>
/// Determines if the content should be initially shown centered over the View that raised the interaction request or not.
/// </summary>
public static readonly DependencyProperty CenterOverAssociatedObjectProperty =
DependencyProperty.Register("CenterOverAssociatedObject", typeof(bool), typeof(PopupWindowAction), new PropertyMetadata(null));
/// <summary>
/// Determines whether the multiple Notification Windows should be allowed.
/// </summary>
public static readonly DependencyProperty AllowMultipleNotificationWindowsProperty =
DependencyProperty.Register("AllowMultipleNotificationWindows", typeof(bool), typeof(PopupWindowAction), new PropertyMetadata(null));
///// <summary>
///// Determines timeout interval in milliseconds (0 = no timeout).
///// </summary>
//public static readonly DependencyProperty TimeoutIntervalProperty =
// DependencyProperty.Register("AutoCancelInterval", typeof(int), typeof(PopupWindowAction), new PropertyMetadata(0));
///// <summary>
///// Determines result if timeout occurs.
///// </summary>
//public static readonly ResultEnum TimeoutResultProperty =
// DependencyProperty.Register("TimeoutResult", typeof(ResultEnum), typeof(PopupWindowAction), new PropertyMetadata(ResultEnum.Cancel));
#endregion
#region Getters and Setters
/// <summary>
/// Gets or sets the content of the window.
/// </summary>
public FrameworkElement WindowContent
{
get => (FrameworkElement)GetValue(WindowContentProperty);
set => SetValue(WindowContentProperty, value);
}
/// <summary>
/// Gets or sets the content template for the window.
/// </summary>
public DataTemplate ContentTemplate
{
get => (DataTemplate)GetValue(ContentTemplateProperty);
set => SetValue(ContentTemplateProperty, value);
}
/// <summary>
/// Gets or sets a value indicating whether the window will be modal or not.
/// </summary>
public bool IsModal
{
get => (bool)GetValue(IsModalProperty);
set => SetValue(IsModalProperty, value);
}
/// <summary>
/// Gets or sets a value whether the window is shown centered over associated object, the screen or WindowsDefault.
/// </summary>
public WindowPositions StartupPosition
{
get => (WindowPositions)GetValue(StartupPositionProperty);
set => SetValue(StartupPositionProperty, value);
}
/// <summary>
/// Gets or sets a value whether the multiple Notification Windows should be allowed.
/// This property can be used for the popup window of type <see cref="NotificationWindow"/> only.
/// </summary>
public bool AllowMultipleNotificationWindows
{
get => (bool)GetValue(AllowMultipleNotificationWindowsProperty);
set => SetValue(AllowMultipleNotificationWindowsProperty, value);
}
///// <summary>
///// Gets or sets a value indicating number of milliseconds before dialog times out (0 = no timeout).
///// </summary>
//public int TimeoutInterval
//{
// get { return (int)GetValue(TimeoutIntervalProperty); }
// set { SetValue(TimeoutIntervalProperty, value); }
//}
///// <summary>
///// Gets or sets a value indicating number of milliseconds before dialog times out (0 = no timeout).
///// </summary>
//public ResultEnum TimeoutResult
//{
// get { return (ResultEnum)GetValue(TimeoutResultProperty); }
// set { SetValue(TimeoutResultProperty, value); }
//}
#endregion
#region PopupWindowAction logic
/// <summary>
/// Displays the child window and collects results for <see cref="IInteractionRequest"/>.
/// </summary>
/// <param name="parameter">The parameter to the action. If the action does not require a parameter, the parameter may be set to a null reference.</param>
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(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();
}
}
/// <summary>
/// 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.
/// </summary>
/// <param name="notification">The notification to be set as a DataContext in the HostWindow.</param>
/// <param name="wrapperWindow">The HostWindow</param>
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
/// <summary>
/// Returns the window to display as part of the trigger action.
/// </summary>
/// <param name="notification">The notification to be set as a DataContext in the window.</param>
/// <returns></returns>
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;
}
/// <summary>
/// When no WindowContent is sent this method is used to create a Notification/Confirmation window to show
/// the corresponding <see cref="Notification"/> or <see cref="Confirmation"/>.
/// </summary>
/// <param name="notification">The Notification or Confirmation parameter to show.</param>
/// <returns></returns>
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;
}
/// <summary>
/// Gets the <see cref="Uri"/> for the notification image.
/// </summary>
/// <param name="windowImage">The popup window's symbol.</param>
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
}
}