399 lines
16 KiB
C#
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
|
|
}
|
|
} |