using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Input;
using System.Windows.Threading;
using MaterialDesignThemes.Wpf.Transitions;
namespace MaterialDesignThemes.Wpf
{
///
/// Defines how a data context is sourced for a dialog if a
/// is passed as the command parameter when using .
///
public enum DialogHostOpenDialogCommandDataContextSource
{
///
/// The data context from the sender element (typically a )
/// is applied to the content.
///
SenderElement,
///
/// The data context from the is applied to the content.
///
DialogHostInstance,
///
/// The data context is explicitly set to null .
///
None
}
[TemplatePart(Name = PopupPartName, Type = typeof(Popup))]
[TemplatePart(Name = PopupPartName, Type = typeof(ContentControl))]
[TemplatePart(Name = ContentCoverGridName, Type = typeof(Grid))]
[TemplateVisualState(GroupName = "PopupStates", Name = OpenStateName)]
[TemplateVisualState(GroupName = "PopupStates", Name = ClosedStateName)]
public class DialogHost : ContentControl
{
public const string PopupPartName = "PART_Popup";
public const string PopupContentPartName = "PART_PopupContentElement";
public const string ContentCoverGridName = "PART_ContentCoverGrid";
public const string OpenStateName = "Open";
public const string ClosedStateName = "Closed";
///
/// Routed command to be used somewhere inside an instance to trigger showing of the dialog. Content can be passed to the dialog via a .
///
public static RoutedCommand OpenDialogCommand = new RoutedCommand();
///
/// Routed command to be used inside dialog content to close a dialog. Use a to indicate the result of the parameter.
///
public static RoutedCommand CloseDialogCommand = new RoutedCommand();
private static readonly HashSet LoadedInstances = new HashSet();
private readonly ManualResetEvent _asyncShowWaitHandle = new ManualResetEvent(false);
private DialogOpenedEventHandler _asyncShowOpenedEventHandler;
private DialogClosingEventHandler _asyncShowClosingEventHandler;
private Popup _popup;
private ContentControl _popupContentControl;
private Grid _contentCoverGrid;
private DialogSession _session;
private DialogOpenedEventHandler _attachedDialogOpenedEventHandler;
private DialogClosingEventHandler _attachedDialogClosingEventHandler;
private object _closeDialogExecutionParameter;
private IInputElement _restoreFocusDialogClose;
private IInputElement _restoreFocusWindowReactivation;
private Action _currentSnackbarMessageQueueUnPauseAction = null;
private Action _closeCleanUp = () => { };
static DialogHost()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(DialogHost), new FrameworkPropertyMetadata(typeof(DialogHost)));
}
#region .Show overloads
///
/// Shows a modal dialog. To use, a instance must be in a visual tree (typically this may be specified towards the root of a Window's XAML).
///
/// Content to show (can be a control or view model).
/// Task result is the parameter used to close the dialog, typically what is passed to the command.
public static async Task Show(object content)
{
return await Show(content, null, null);
}
///
/// Shows a modal dialog. To use, a instance must be in a visual tree (typically this may be specified towards the root of a Window's XAML).
///
/// Content to show (can be a control or view model).
/// Allows access to opened event which would otherwise have been subscribed to on a instance.
/// Task result is the parameter used to close the dialog, typically what is passed to the command.
public static async Task Show(object content, DialogOpenedEventHandler openedEventHandler)
{
return await Show(content, null, openedEventHandler, null);
}
///
/// Shows a modal dialog. To use, a instance must be in a visual tree (typically this may be specified towards the root of a Window's XAML).
///
/// Content to show (can be a control or view model).
/// Allows access to closing event which would otherwise have been subscribed to on a instance.
/// Task result is the parameter used to close the dialog, typically what is passed to the command.
public static async Task Show(object content, DialogClosingEventHandler closingEventHandler)
{
return await Show(content, null, null, closingEventHandler);
}
///
/// Shows a modal dialog. To use, a instance must be in a visual tree (typically this may be specified towards the root of a Window's XAML).
///
/// Content to show (can be a control or view model).
/// Allows access to opened event which would otherwise have been subscribed to on a instance.
/// Allows access to closing event which would otherwise have been subscribed to on a instance.
/// Task result is the parameter used to close the dialog, typically what is passed to the command.
public static async Task Show(object content, DialogOpenedEventHandler openedEventHandler, DialogClosingEventHandler closingEventHandler)
{
return await Show(content, null, openedEventHandler, closingEventHandler);
}
///
/// Shows a modal dialog. To use, a instance must be in a visual tree (typically this may be specified towards the root of a Window's XAML).
///
/// Content to show (can be a control or view model).
/// of the instance where the dialog should be shown. Typically this will match an identifer set in XAML. null is allowed.
/// Task result is the parameter used to close the dialog, typically what is passed to the command.
public static async Task Show(object content, object dialogIdentifier)
{
return await Show(content, dialogIdentifier, null, null);
}
///
/// Shows a modal dialog. To use, a instance must be in a visual tree (typically this may be specified towards the root of a Window's XAML).
///
/// Content to show (can be a control or view model).
/// of the instance where the dialog should be shown. Typically this will match an identifer set in XAML. null is allowed.
/// Allows access to opened event which would otherwise have been subscribed to on a instance.
/// Task result is the parameter used to close the dialog, typically what is passed to the command.
public static Task Show(object content, object dialogIdentifier, DialogOpenedEventHandler openedEventHandler)
{
return Show(content, dialogIdentifier, openedEventHandler, null);
}
///
/// Shows a modal dialog. To use, a instance must be in a visual tree (typically this may be specified towards the root of a Window's XAML).
///
/// Content to show (can be a control or view model).
/// of the instance where the dialog should be shown. Typically this will match an identifer set in XAML. null is allowed.
/// Allows access to closing event which would otherwise have been subscribed to on a instance.
/// Task result is the parameter used to close the dialog, typically what is passed to the command.
public static Task Show(object content, object dialogIdentifier, DialogClosingEventHandler closingEventHandler)
{
return Show(content, dialogIdentifier, null, closingEventHandler);
}
///
/// Shows a modal dialog. To use, a instance must be in a visual tree (typically this may be specified towards the root of a Window's XAML).
///
/// Content to show (can be a control or view model).
/// of the instance where the dialog should be shown. Typically this will match an identifer set in XAML. null is allowed.
/// Allows access to opened event which would otherwise have been subscribed to on a instance.
/// Allows access to closing event which would otherwise have been subscribed to on a instance.
/// Task result is the parameter used to close the dialog, typically what is passed to the command.
public static async Task Show(object content, object dialogIdentifier, DialogOpenedEventHandler openedEventHandler, DialogClosingEventHandler closingEventHandler)
{
if (content == null) throw new ArgumentNullException(nameof(content));
if (LoadedInstances.Count == 0)
throw new InvalidOperationException("No loaded DialogHost instances.");
LoadedInstances.First().Dispatcher.VerifyAccess();
var targets = LoadedInstances.Where(dh => dialogIdentifier == null || Equals(dh.Identifier, dialogIdentifier)).ToList();
if (targets.Count == 0)
throw new InvalidOperationException("No loaded DialogHost have an Identifier property matching dialogIndetifier argument.");
if (targets.Count > 1)
throw new InvalidOperationException("Multiple viable DialogHosts. Specify a unique Identifier on each DialogHost, especially where multiple Windows are a concern.");
return await targets[0].ShowInternal(content, openedEventHandler, closingEventHandler);
}
internal async Task ShowInternal(object content, DialogOpenedEventHandler openedEventHandler, DialogClosingEventHandler closingEventHandler)
{
if (IsOpen)
throw new InvalidOperationException("DialogHost is already open.");
AssertTargetableContent();
DialogContent = content;
_asyncShowOpenedEventHandler = openedEventHandler;
_asyncShowClosingEventHandler = closingEventHandler;
SetCurrentValue(IsOpenProperty, true);
var task = new Task(() =>
{
_asyncShowWaitHandle.WaitOne();
});
task.Start();
await task;
_asyncShowOpenedEventHandler = null;
_asyncShowClosingEventHandler = null;
return _closeDialogExecutionParameter;
}
#endregion
public DialogHost()
{
Loaded += OnLoaded;
Unloaded += OnUnloaded;
CommandBindings.Add(new CommandBinding(CloseDialogCommand, CloseDialogHandler, CloseDialogCanExecute));
CommandBindings.Add(new CommandBinding(OpenDialogCommand, OpenDialogHandler));
}
public static readonly DependencyProperty IdentifierProperty = DependencyProperty.Register(
nameof(Identifier), typeof (object), typeof (DialogHost), new PropertyMetadata(default(object)));
///
/// Identifier which is used in conjunction with to determine where a dialog should be shown.
///
public object Identifier
{
get { return GetValue(IdentifierProperty); }
set { SetValue(IdentifierProperty, value); }
}
public static readonly DependencyProperty IsOpenProperty = DependencyProperty.Register(
nameof(IsOpen), typeof (bool), typeof (DialogHost), new FrameworkPropertyMetadata(default(bool), FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, IsOpenPropertyChangedCallback));
private static void IsOpenPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var dialogHost = (DialogHost)dependencyObject;
if (dialogHost._popupContentControl != null)
ValidationAssist.SetSuppress(dialogHost._popupContentControl, !dialogHost.IsOpen);
VisualStateManager.GoToState(dialogHost, dialogHost.SelectState(), !TransitionAssist.GetDisableTransitions(dialogHost));
if (dialogHost.IsOpen)
{
WatchWindowActivation(dialogHost);
dialogHost._currentSnackbarMessageQueueUnPauseAction = dialogHost.SnackbarMessageQueue?.Pause();
}
else
{
dialogHost._asyncShowWaitHandle.Set();
dialogHost._attachedDialogClosingEventHandler = null;
if (dialogHost._currentSnackbarMessageQueueUnPauseAction != null)
{
dialogHost._currentSnackbarMessageQueueUnPauseAction();
dialogHost._currentSnackbarMessageQueueUnPauseAction = null;
}
dialogHost._session.IsEnded = true;
dialogHost._session = null;
dialogHost._closeCleanUp();
// Don't attempt to Invoke if _restoreFocusDialogClose hasn't been assigned yet. Can occur
// if the MainWindow has started up minimized. Even when Show() has been called, this doesn't
// seem to have been set.
dialogHost.Dispatcher.InvokeAsync(() => dialogHost._restoreFocusDialogClose?.Focus(), DispatcherPriority.Input);
return;
}
dialogHost._asyncShowWaitHandle.Reset();
dialogHost._session = new DialogSession(dialogHost);
var window = Window.GetWindow(dialogHost);
dialogHost._restoreFocusDialogClose = window != null ? FocusManager.GetFocusedElement(window) : null;
//multiple ways of calling back that the dialog has opened:
// * routed event
// * the attached property (which should be applied to the button which opened the dialog
// * straight forward dependency property
// * handler provided to the async show method
var dialogOpenedEventArgs = new DialogOpenedEventArgs(dialogHost._session, DialogOpenedEvent);
dialogHost.OnDialogOpened(dialogOpenedEventArgs);
dialogHost._attachedDialogOpenedEventHandler?.Invoke(dialogHost, dialogOpenedEventArgs);
dialogHost.DialogOpenedCallback?.Invoke(dialogHost, dialogOpenedEventArgs);
dialogHost._asyncShowOpenedEventHandler?.Invoke(dialogHost, dialogOpenedEventArgs);
dialogHost.Dispatcher.BeginInvoke(DispatcherPriority.Background, new Action(() =>
{
CommandManager.InvalidateRequerySuggested();
var child = dialogHost.FocusPopup();
//https://github.com/ButchersBoy/MaterialDesignInXamlToolkit/issues/187
//totally not happy about this, but on immediate validation we can get some weird looking stuff...give WPF a kick to refresh...
Task.Delay(300).ContinueWith(t => child.Dispatcher.BeginInvoke(new Action(() => child.InvalidateVisual())));
}));
}
public bool IsOpen
{
get { return (bool)GetValue(IsOpenProperty); }
set { SetValue(IsOpenProperty, value); }
}
public static readonly DependencyProperty DialogContentProperty = DependencyProperty.Register(
nameof(DialogContent), typeof (object), typeof (DialogHost), new PropertyMetadata(default(object)));
public object DialogContent
{
get { return (object)GetValue(DialogContentProperty); }
set { SetValue(DialogContentProperty, value); }
}
public static readonly DependencyProperty DialogContentTemplateProperty = DependencyProperty.Register(
nameof(DialogContentTemplate), typeof (DataTemplate), typeof (DialogHost), new PropertyMetadata(default(DataTemplate)));
public DataTemplate DialogContentTemplate
{
get { return (DataTemplate)GetValue(DialogContentTemplateProperty); }
set { SetValue(DialogContentTemplateProperty, value); }
}
public static readonly DependencyProperty DialogContentTemplateSelectorProperty = DependencyProperty.Register(
nameof(DialogContentTemplateSelector), typeof (DataTemplateSelector), typeof (DialogHost), new PropertyMetadata(default(DataTemplateSelector)));
public DataTemplateSelector DialogContentTemplateSelector
{
get { return (DataTemplateSelector)GetValue(DialogContentTemplateSelectorProperty); }
set { SetValue(DialogContentTemplateSelectorProperty, value); }
}
public static readonly DependencyProperty DialogContentStringFormatProperty = DependencyProperty.Register(
nameof(DialogContentStringFormat), typeof (string), typeof (DialogHost), new PropertyMetadata(default(string)));
public string DialogContentStringFormat
{
get { return (string)GetValue(DialogContentStringFormatProperty); }
set { SetValue(DialogContentStringFormatProperty, value); }
}
public static readonly DependencyProperty DialogMarginProperty = DependencyProperty.Register(
"DialogMargin", typeof(Thickness), typeof(DialogHost), new PropertyMetadata(default(Thickness)));
public Thickness DialogMargin
{
get { return (Thickness)GetValue(DialogMarginProperty); }
set { SetValue(DialogMarginProperty, value); }
}
public static readonly DependencyProperty OpenDialogCommandDataContextSourceProperty = DependencyProperty.Register(
nameof(OpenDialogCommandDataContextSource), typeof (DialogHostOpenDialogCommandDataContextSource), typeof (DialogHost), new PropertyMetadata(default(DialogHostOpenDialogCommandDataContextSource)));
///
/// Defines how a data context is sourced for a dialog if a
/// is passed as the command parameter when using .
///
public DialogHostOpenDialogCommandDataContextSource OpenDialogCommandDataContextSource
{
get { return (DialogHostOpenDialogCommandDataContextSource)GetValue(OpenDialogCommandDataContextSourceProperty); }
set { SetValue(OpenDialogCommandDataContextSourceProperty, value); }
}
public static readonly DependencyProperty CloseOnClickAwayProperty = DependencyProperty.Register(
"CloseOnClickAway", typeof (bool), typeof (DialogHost), new PropertyMetadata(default(bool)));
///
/// Indicates whether the dialog will close if the user clicks off the dialog, on the obscured background.
///
public bool CloseOnClickAway
{
get { return (bool)GetValue(CloseOnClickAwayProperty); }
set { SetValue(CloseOnClickAwayProperty, value); }
}
public static readonly DependencyProperty CloseOnClickAwayParameterProperty = DependencyProperty.Register(
"CloseOnClickAwayParameter", typeof (object), typeof (DialogHost), new PropertyMetadata(default(object)));
///
/// Parameter to provide to close handlers if an close due to click away is instigated.
///
public object CloseOnClickAwayParameter
{
get { return (object)GetValue(CloseOnClickAwayParameterProperty); }
set { SetValue(CloseOnClickAwayParameterProperty, value); }
}
public static readonly DependencyProperty SnackbarMessageQueueProperty = DependencyProperty.Register(
"SnackbarMessageQueue", typeof(SnackbarMessageQueue), typeof(DialogHost), new PropertyMetadata(default(SnackbarMessageQueue), SnackbarMessageQueuePropertyChangedCallback));
private static void SnackbarMessageQueuePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
var dialogHost = (DialogHost) dependencyObject;
if (dialogHost._currentSnackbarMessageQueueUnPauseAction != null)
{
dialogHost._currentSnackbarMessageQueueUnPauseAction();
dialogHost._currentSnackbarMessageQueueUnPauseAction = null;
}
if (!dialogHost.IsOpen) return;
var snackbarMessageQueue = dependencyPropertyChangedEventArgs.NewValue as SnackbarMessageQueue;
dialogHost._currentSnackbarMessageQueueUnPauseAction = snackbarMessageQueue?.Pause();
}
///
/// Allows association of a snackbar, so that notifications can be paused whilst a dialog is being displayed.
///
public SnackbarMessageQueue SnackbarMessageQueue
{
get { return (SnackbarMessageQueue)GetValue(SnackbarMessageQueueProperty); }
set { SetValue(SnackbarMessageQueueProperty, value); }
}
public static readonly DependencyProperty PopupStyleProperty = DependencyProperty.Register(
nameof(PopupStyle), typeof(Style), typeof(DialogHost), new PropertyMetadata(default(Style)));
public Style PopupStyle
{
get { return (Style) GetValue(PopupStyleProperty); }
set { SetValue(PopupStyleProperty, value); }
}
public override void OnApplyTemplate()
{
if (_contentCoverGrid != null)
_contentCoverGrid.MouseLeftButtonUp -= ContentCoverGridOnMouseLeftButtonUp;
_popup = GetTemplateChild(PopupPartName) as Popup;
_popupContentControl = GetTemplateChild(PopupContentPartName) as ContentControl;
_contentCoverGrid = GetTemplateChild(ContentCoverGridName) as Grid;
if (_contentCoverGrid != null)
_contentCoverGrid.MouseLeftButtonUp += ContentCoverGridOnMouseLeftButtonUp;
VisualStateManager.GoToState(this, SelectState(), false);
base.OnApplyTemplate();
}
#region open dialog events/callbacks
public static readonly RoutedEvent DialogOpenedEvent =
EventManager.RegisterRoutedEvent(
"DialogOpened",
RoutingStrategy.Bubble,
typeof (DialogOpenedEventHandler),
typeof (DialogHost));
///
/// Raised when a dialog is opened.
///
public event DialogOpenedEventHandler DialogOpened
{
add { AddHandler(DialogOpenedEvent, value); }
remove { RemoveHandler(DialogOpenedEvent, value); }
}
///
/// Attached property which can be used on the which instigated the to process the event.
///
public static readonly DependencyProperty DialogOpenedAttachedProperty = DependencyProperty.RegisterAttached(
"DialogOpenedAttached", typeof(DialogOpenedEventHandler), typeof(DialogHost), new PropertyMetadata(default(DialogOpenedEventHandler)));
public static void SetDialogOpenedAttached(DependencyObject element, DialogOpenedEventHandler value)
{
element.SetValue(DialogOpenedAttachedProperty, value);
}
public static DialogOpenedEventHandler GetDialogOpenedAttached(DependencyObject element)
{
return (DialogOpenedEventHandler)element.GetValue(DialogOpenedAttachedProperty);
}
public static readonly DependencyProperty DialogOpenedCallbackProperty = DependencyProperty.Register(
nameof(DialogOpenedCallback), typeof(DialogOpenedEventHandler), typeof(DialogHost), new PropertyMetadata(default(DialogOpenedEventHandler)));
///
/// Callback fired when the event is fired, allowing the event to be processed from a binding/view model.
///
public DialogOpenedEventHandler DialogOpenedCallback
{
get { return (DialogOpenedEventHandler)GetValue(DialogOpenedCallbackProperty); }
set { SetValue(DialogOpenedCallbackProperty, value); }
}
protected void OnDialogOpened(DialogOpenedEventArgs eventArgs)
{
RaiseEvent(eventArgs);
}
#endregion
#region close dialog events/callbacks
public static readonly RoutedEvent DialogClosingEvent =
EventManager.RegisterRoutedEvent(
"DialogClosing",
RoutingStrategy.Bubble,
typeof (DialogClosingEventHandler),
typeof (DialogHost));
///
/// Raised just before a dialog is closed.
///
public event DialogClosingEventHandler DialogClosing
{
add { AddHandler(DialogClosingEvent, value); }
remove { RemoveHandler(DialogClosingEvent, value); }
}
///
/// Attached property which can be used on the which instigated the to process the closing event.
///
public static readonly DependencyProperty DialogClosingAttachedProperty = DependencyProperty.RegisterAttached(
"DialogClosingAttached", typeof (DialogClosingEventHandler), typeof (DialogHost), new PropertyMetadata(default(DialogClosingEventHandler)));
public static void SetDialogClosingAttached(DependencyObject element, DialogClosingEventHandler value)
{
element.SetValue(DialogClosingAttachedProperty, value);
}
public static DialogClosingEventHandler GetDialogClosingAttached(DependencyObject element)
{
return (DialogClosingEventHandler)element.GetValue(DialogClosingAttachedProperty);
}
public static readonly DependencyProperty DialogClosingCallbackProperty = DependencyProperty.Register(
nameof(DialogClosingCallback), typeof (DialogClosingEventHandler), typeof (DialogHost), new PropertyMetadata(default(DialogClosingEventHandler)));
///
/// Callback fired when the event is fired, allowing the event to be processed from a binding/view model.
///
public DialogClosingEventHandler DialogClosingCallback
{
get { return (DialogClosingEventHandler)GetValue(DialogClosingCallbackProperty); }
set { SetValue(DialogClosingCallbackProperty, value); }
}
protected void OnDialogClosing(DialogClosingEventArgs eventArgs)
{
RaiseEvent(eventArgs);
}
#endregion
internal void AssertTargetableContent()
{
var existindBinding = BindingOperations.GetBindingExpression(this, DialogContentProperty);
if (existindBinding != null)
throw new InvalidOperationException(
"Content cannot be passed to a dialog via the OpenDialog if DialogContent already has a binding.");
}
internal void Close(object parameter)
{
var dialogClosingEventArgs = new DialogClosingEventArgs(_session, parameter, DialogClosingEvent);
_session.IsEnded = true;
//multiple ways of calling back that the dialog is closing:
// * routed event
// * the attached property (which should be applied to the button which opened the dialog
// * straight forward dependency property
// * handler provided to the async show method
OnDialogClosing(dialogClosingEventArgs);
_attachedDialogClosingEventHandler?.Invoke(this, dialogClosingEventArgs);
DialogClosingCallback?.Invoke(this, dialogClosingEventArgs);
_asyncShowClosingEventHandler?.Invoke(this, dialogClosingEventArgs);
if (!dialogClosingEventArgs.IsCancelled)
SetCurrentValue(IsOpenProperty, false);
else
_session.IsEnded = false;
_closeDialogExecutionParameter = parameter;
}
///
/// Attempts to focus the content of a popup.
///
/// The popup content.
internal UIElement FocusPopup()
{
var child = _popup?.Child;
if (child == null) return null;
CommandManager.InvalidateRequerySuggested();
var focusable = child.VisualDepthFirstTraversal().OfType().FirstOrDefault(ui => ui.Focusable && ui.IsVisible);
focusable?.Dispatcher.InvokeAsync(() =>
{
if (!focusable.Focus()) return;
focusable.MoveFocus(new TraversalRequest(FocusNavigationDirection.First));
}, DispatcherPriority.Background);
return child;
}
protected override void OnPreviewMouseDown(MouseButtonEventArgs e)
{
var window = Window.GetWindow(this);
if (window != null && !window.IsActive)
window.Activate();
base.OnPreviewMouseDown(e);
}
private void ContentCoverGridOnMouseLeftButtonUp(object sender, MouseButtonEventArgs mouseButtonEventArgs)
{
if (CloseOnClickAway)
Close(CloseOnClickAwayParameter);
}
private void OpenDialogHandler(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
{
if (executedRoutedEventArgs.Handled) return;
var dependencyObject = executedRoutedEventArgs.OriginalSource as DependencyObject;
if (dependencyObject != null)
{
_attachedDialogOpenedEventHandler = GetDialogOpenedAttached(dependencyObject);
_attachedDialogClosingEventHandler = GetDialogClosingAttached(dependencyObject);
}
if (executedRoutedEventArgs.Parameter != null)
{
AssertTargetableContent();
if (_popupContentControl != null)
{
switch (OpenDialogCommandDataContextSource)
{
case DialogHostOpenDialogCommandDataContextSource.SenderElement:
_popupContentControl.DataContext =
(executedRoutedEventArgs.OriginalSource as FrameworkElement)?.DataContext;
break;
case DialogHostOpenDialogCommandDataContextSource.DialogHostInstance:
_popupContentControl.DataContext = DataContext;
break;
case DialogHostOpenDialogCommandDataContextSource.None:
_popupContentControl.DataContext = null;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
DialogContent = executedRoutedEventArgs.Parameter;
}
SetCurrentValue(IsOpenProperty, true);
executedRoutedEventArgs.Handled = true;
}
private void CloseDialogCanExecute(object sender, CanExecuteRoutedEventArgs canExecuteRoutedEventArgs)
{
canExecuteRoutedEventArgs.CanExecute = _session != null;
}
private void CloseDialogHandler(object sender, ExecutedRoutedEventArgs executedRoutedEventArgs)
{
if (executedRoutedEventArgs.Handled) return;
Close(executedRoutedEventArgs.Parameter);
executedRoutedEventArgs.Handled = true;
}
private string SelectState()
{
return IsOpen ? OpenStateName : ClosedStateName;
}
private void OnUnloaded(object sender, RoutedEventArgs routedEventArgs)
{
LoadedInstances.Remove(this);
SetCurrentValue(IsOpenProperty, false);
}
private void OnLoaded(object sender, RoutedEventArgs routedEventArgs)
{
LoadedInstances.Add(this);
}
private static void WatchWindowActivation(DialogHost dialogHost)
{
var window = Window.GetWindow(dialogHost);
if (window != null)
{
window.Activated += dialogHost.WindowOnActivated;
window.Deactivated += dialogHost.WindowOnDeactivated;
dialogHost._closeCleanUp = () =>
{
window.Activated -= dialogHost.WindowOnActivated;
window.Deactivated -= dialogHost.WindowOnDeactivated;
};
}
else
{
dialogHost._closeCleanUp = () => { };
}
}
private void WindowOnDeactivated(object sender, EventArgs eventArgs)
{
_restoreFocusWindowReactivation = _popup != null ? FocusManager.GetFocusedElement((Window)sender) : null;
}
private void WindowOnActivated(object sender, EventArgs eventArgs)
{
if (_restoreFocusWindowReactivation != null)
{
Dispatcher.BeginInvoke(new Action(() =>
{
Keyboard.Focus(_restoreFocusWindowReactivation);
}));
}
}
}
}