Skip to content

Commit

Permalink
Merge pull request #2009 from thoemmi/multiple-dialogs
Browse files Browse the repository at this point in the history
support for multiple dialogs (fixes #1974)
  • Loading branch information
punker76 committed Jun 30, 2015
2 parents cb793ea + 6992b9a commit 500d535
Show file tree
Hide file tree
Showing 7 changed files with 107 additions and 42 deletions.
56 changes: 44 additions & 12 deletions MahApps.Metro/Controls/Dialogs/DialogManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using MahApps.Metro.Behaviours;

namespace MahApps.Metro.Controls.Dialogs
{
Expand Down Expand Up @@ -65,7 +64,7 @@ public static Task<LoginDialogData> ShowLoginAsync(this MetroWindow window, stri
{
window.SizeChanged -= sizeHandler;
window.metroDialogContainer.Children.Remove(dialog); //remove the dialog from the container
window.RemoveDialog(dialog);
return HandleOverlayOnHide(settings, window);
//window.overlayBox.Visibility = System.Windows.Visibility.Hidden; //deactive the overlay effect
Expand Down Expand Up @@ -131,7 +130,7 @@ public static Task<string> ShowInputAsync(this MetroWindow window, string title,
{
window.SizeChanged -= sizeHandler;
window.metroDialogContainer.Children.Remove(dialog); //remove the dialog from the container
window.RemoveDialog(dialog);
return HandleOverlayOnHide(settings, window);
}))).ContinueWith(y3 => y).Unwrap();
Expand Down Expand Up @@ -198,7 +197,7 @@ public static Task<MessageDialogResult> ShowMessageAsync(this MetroWindow window
{
window.SizeChanged -= sizeHandler;
window.metroDialogContainer.Children.Remove(dialog); //remove the dialog from the container
window.RemoveDialog(dialog);
return HandleOverlayOnHide(settings, window);
}))).ContinueWith(y3 => y).Unwrap();
Expand Down Expand Up @@ -266,7 +265,7 @@ public static Task<ProgressDialogController> ShowProgressAsync(this MetroWindow
{
window.SizeChanged -= sizeHandler;
window.metroDialogContainer.Children.Remove(dialog); //remove the dialog from the container
window.RemoveDialog(dialog);
return HandleOverlayOnHide(settings, window);
}));
Expand All @@ -279,7 +278,7 @@ public static Task<ProgressDialogController> ShowProgressAsync(this MetroWindow

private static Task HandleOverlayOnHide(MetroDialogSettings settings, MetroWindow window)
{
if (window.metroDialogContainer.Children.Count == 0)
if (window.metroActiveDialogContainer.Children.Count == 0)
{
return (settings == null || settings.AnimateHide ? window.HideOverlayAsync() : Task.Factory.StartNew(() => window.Dispatcher.Invoke(new Action(window.HideOverlay))));
}
Expand All @@ -293,7 +292,7 @@ private static Task HandleOverlayOnHide(MetroDialogSettings settings, MetroWindo

private static Task HandleOverlayOnShow(MetroDialogSettings settings, MetroWindow window)
{
if (window.metroDialogContainer.Children.Count == 0)
if (window.metroActiveDialogContainer.Children.Count == 0)
{
return (settings == null || settings.AnimateShow ? window.ShowOverlayAsync() : Task.Factory.StartNew(() => window.Dispatcher.Invoke(new Action(window.ShowOverlay))));
}
Expand All @@ -319,7 +318,7 @@ public static Task ShowMetroDialogAsync(this MetroWindow window, BaseMetroDialog
MetroDialogSettings settings = null)
{
window.Dispatcher.VerifyAccess();
if (window.metroDialogContainer.Children.Contains(dialog))
if (window.metroActiveDialogContainer.Children.Contains(dialog) || window.metroInactiveDialogContainer.Children.Contains(dialog))
throw new InvalidOperationException("The provided dialog is already visible in the specified window.");

return HandleOverlayOnShow(settings, window).ContinueWith(z =>
Expand Down Expand Up @@ -357,7 +356,7 @@ public static Task ShowMetroDialogAsync(this MetroWindow window, BaseMetroDialog
public static Task HideMetroDialogAsync(this MetroWindow window, BaseMetroDialog dialog, MetroDialogSettings settings = null)
{
window.Dispatcher.VerifyAccess();
if (!window.metroDialogContainer.Children.Contains(dialog))
if (!window.metroActiveDialogContainer.Children.Contains(dialog) && !window.metroInactiveDialogContainer.Children.Contains(dialog))
throw new InvalidOperationException("The provided dialog is not visible in the specified window.");

window.SizeChanged -= dialog.SizeChangedHandler;
Expand All @@ -374,7 +373,7 @@ public static Task HideMetroDialogAsync(this MetroWindow window, BaseMetroDialog
return (Task)window.Dispatcher.Invoke(new Func<Task>(() =>
{
window.metroDialogContainer.Children.Remove(dialog); //remove the dialog from the container
window.RemoveDialog(dialog);
return HandleOverlayOnHide(settings,window);
}));
Expand All @@ -391,7 +390,7 @@ public static Task<TDialog> GetCurrentDialogAsync<TDialog>(this MetroWindow wind
var t = new TaskCompletionSource<TDialog>();
window.Dispatcher.Invoke((Action)(() =>
{
TDialog dialog = window.metroDialogContainer.Children.OfType<TDialog>().LastOrDefault();
TDialog dialog = window.metroActiveDialogContainer.Children.OfType<TDialog>().LastOrDefault();
t.TrySetResult(dialog);
}));
return t.Task;
Expand All @@ -411,13 +410,46 @@ private static SizeChangedEventHandler SetupAndOpenDialog(MetroWindow window, Ba

window.SizeChanged += sizeHandler;

window.metroDialogContainer.Children.Add(dialog); //add the dialog to the container
window.AddDialog(dialog);

dialog.OnShown();

return sizeHandler;
}

private static void AddDialog(this MetroWindow window, BaseMetroDialog dialog)
{
// if there's already an active dialog, move to the background
var activeDialog = window.metroActiveDialogContainer.Children.Cast<UIElement>().SingleOrDefault();
if (activeDialog != null)
{
window.metroActiveDialogContainer.Children.Remove(activeDialog);
window.metroInactiveDialogContainer.Children.Add(activeDialog);
}

window.metroActiveDialogContainer.Children.Add(dialog); //add the dialog to the container}
}

private static void RemoveDialog(this MetroWindow window, BaseMetroDialog dialog)
{
if (window.metroActiveDialogContainer.Children.Contains(dialog))
{
window.metroActiveDialogContainer.Children.Remove(dialog); //remove the dialog from the container

// if there's an inactive dialog, bring it to the front
var dlg = window.metroInactiveDialogContainer.Children.Cast<UIElement>().LastOrDefault();
if (dlg != null)
{
window.metroInactiveDialogContainer.Children.Remove(dlg);
window.metroActiveDialogContainer.Children.Add(dlg);
}
}
else
{
window.metroInactiveDialogContainer.Children.Remove(dialog);
}
}

public static BaseMetroDialog ShowDialogExternally(this BaseMetroDialog dialog)
{
Window win = SetupExternalDialogWindow(dialog);
Expand Down
40 changes: 22 additions & 18 deletions MahApps.Metro/Controls/MetroWindow.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,8 @@ namespace MahApps.Metro.Controls
[TemplatePart(Name = PART_RightWindowCommands, Type = typeof(WindowCommands))]
[TemplatePart(Name = PART_WindowButtonCommands, Type = typeof(WindowButtonCommands))]
[TemplatePart(Name = PART_OverlayBox, Type = typeof(Grid))]
[TemplatePart(Name = PART_MetroDialogContainer, Type = typeof(Grid))]
[TemplatePart(Name = PART_MetroActiveDialogContainer, Type = typeof(Grid))]
[TemplatePart(Name = PART_MetroInactiveDialogsContainer, Type = typeof(Grid))]
[TemplatePart(Name = PART_FlyoutModal, Type = typeof(Rectangle))]
public class MetroWindow : Window
{
Expand All @@ -34,7 +35,8 @@ public class MetroWindow : Window
private const string PART_RightWindowCommands = "PART_RightWindowCommands";
private const string PART_WindowButtonCommands = "PART_WindowButtonCommands";
private const string PART_OverlayBox = "PART_OverlayBox";
private const string PART_MetroDialogContainer = "PART_MetroDialogContainer";
private const string PART_MetroActiveDialogContainer = "PART_MetroActiveDialogContainer";
private const string PART_MetroInactiveDialogsContainer = "PART_MetroInactiveDialogsContainer";
private const string PART_FlyoutModal = "PART_FlyoutModal";

public static readonly DependencyProperty ShowIconOnTitleBarProperty = DependencyProperty.Register("ShowIconOnTitleBar", typeof(bool), typeof(MetroWindow), new PropertyMetadata(true, OnShowIconOnTitleBarPropertyChangedCallback));
Expand Down Expand Up @@ -70,7 +72,7 @@ public class MetroWindow : Window

public static readonly DependencyProperty IconTemplateProperty = DependencyProperty.Register("IconTemplate", typeof(DataTemplate), typeof(MetroWindow), new PropertyMetadata(null));
public static readonly DependencyProperty TitleTemplateProperty = DependencyProperty.Register("TitleTemplate", typeof(DataTemplate), typeof(MetroWindow), new PropertyMetadata(null));

public static readonly DependencyProperty LeftWindowCommandsProperty = DependencyProperty.Register("LeftWindowCommands", typeof(WindowCommands), typeof(MetroWindow), new PropertyMetadata(null));
public static readonly DependencyProperty RightWindowCommandsProperty = DependencyProperty.Register("RightWindowCommands", typeof(WindowCommands), typeof(MetroWindow), new PropertyMetadata(null));

Expand All @@ -82,7 +84,7 @@ public class MetroWindow : Window
public static readonly DependencyProperty WindowMinButtonStyleProperty = DependencyProperty.Register("WindowMinButtonStyle", typeof(Style), typeof(MetroWindow), new PropertyMetadata(null));
public static readonly DependencyProperty WindowMaxButtonStyleProperty = DependencyProperty.Register("WindowMaxButtonStyle", typeof(Style), typeof(MetroWindow), new PropertyMetadata(null));
public static readonly DependencyProperty WindowCloseButtonStyleProperty = DependencyProperty.Register("WindowCloseButtonStyle", typeof(Style), typeof(MetroWindow), new PropertyMetadata(null));

public static readonly DependencyProperty UseNoneWindowStyleProperty = DependencyProperty.Register("UseNoneWindowStyle", typeof(bool), typeof(MetroWindow), new PropertyMetadata(false, OnUseNoneWindowStylePropertyChangedCallback));
public static readonly DependencyProperty OverrideDefaultWindowCommandsBrushProperty = DependencyProperty.Register("OverrideDefaultWindowCommandsBrush", typeof(SolidColorBrush), typeof(MetroWindow));

Expand All @@ -96,16 +98,17 @@ public class MetroWindow : Window
internal ContentPresenter LeftWindowCommandsPresenter;
internal ContentPresenter RightWindowCommandsPresenter;
internal WindowButtonCommands WindowButtonCommands;

internal Grid overlayBox;
internal Grid metroDialogContainer;
internal Grid metroActiveDialogContainer;
internal Grid metroInactiveDialogContainer;
private Storyboard overlayStoryboard;
Rectangle flyoutModal;

public static readonly RoutedEvent FlyoutsStatusChangedEvent = EventManager.RegisterRoutedEvent(
"FlyoutsStatusChanged", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(MetroWindow));

// Provide CLR accessors for the event
// Provide CLR accessors for the event
public event RoutedEventHandler FlyoutsStatusChanged
{
add { AddHandler(FlyoutsStatusChangedEvent, value); }
Expand Down Expand Up @@ -446,7 +449,7 @@ public bool IsMinButtonEnabled
get { return (bool)GetValue(IsMinButtonEnabledProperty); }
set { SetValue(IsMinButtonEnabledProperty, value); }
}

/// <summary>
/// Gets/sets if the max/restore button is enabled.
/// </summary>
Expand Down Expand Up @@ -502,7 +505,7 @@ private void SetVisibiltyForIcon()
this.icon.Visibility = iconVisibility;
}
}

private void SetVisibiltyForAllTitleElements(bool visible)
{
this.SetVisibiltyForIcon();
Expand All @@ -527,7 +530,7 @@ private void SetVisibiltyForAllTitleElements(bool visible)
}
if (this.WindowButtonCommands != null)
{
this.WindowButtonCommands.Visibility = this.WindowButtonCommandsOverlayBehavior.HasFlag(WindowCommandsOverlayBehavior.HiddenTitleBar) ?
this.WindowButtonCommands.Visibility = this.WindowButtonCommandsOverlayBehavior.HasFlag(WindowCommandsOverlayBehavior.HiddenTitleBar) ?
Visibility.Visible : newVisibility;
}

Expand Down Expand Up @@ -798,7 +801,7 @@ private void ThemeManagerOnIsThemeChanged(object sender, OnThemeChangedEventArgs
this.HandleWindowCommandsForFlyouts(flyouts);
}
}

private void FlyoutsPreviewMouseDown(object sender, MouseButtonEventArgs e)
{
var element = (e.OriginalSource as DependencyObject);
Expand All @@ -813,7 +816,7 @@ private void FlyoutsPreviewMouseDown(object sender, MouseButtonEventArgs e)
return;
}
}

if (Flyouts.OverrideExternalCloseButton == null)
{
foreach (var flyout in Flyouts.GetFlyouts().Where(x => x.IsOpen && x.ExternalCloseButton == e.ChangedButton && (!x.IsPinned || Flyouts.OverrideIsPinned)))
Expand Down Expand Up @@ -859,8 +862,9 @@ public override void OnApplyTemplate()
}

overlayBox = GetTemplateChild(PART_OverlayBox) as Grid;
metroDialogContainer = GetTemplateChild(PART_MetroDialogContainer) as Grid;
flyoutModal = (Rectangle) GetTemplateChild(PART_FlyoutModal);
metroActiveDialogContainer = GetTemplateChild(PART_MetroActiveDialogContainer) as Grid;
metroInactiveDialogContainer = GetTemplateChild(PART_MetroInactiveDialogsContainer) as Grid;
flyoutModal = (Rectangle)GetTemplateChild(PART_FlyoutModal);
flyoutModal.PreviewMouseDown += FlyoutsPreviewMouseDown;
this.PreviewMouseDown += FlyoutsPreviewMouseDown;

Expand Down Expand Up @@ -952,7 +956,7 @@ protected void TitleBarMouseDown(object sender, MouseButtonEventArgs e)
if (e.ChangedButton == MouseButton.Left && !this.UseNoneWindowStyle)
{
var mPoint = Mouse.GetPosition(this);

if (IsWindowDraggable)
{
IntPtr windowHandle = new WindowInteropHelper(this).Handle;
Expand Down Expand Up @@ -1022,7 +1026,7 @@ private static void ShowSystemMenuPhysicalCoordinates(Window window, Point physi

var hmenu = UnsafeNativeMethods.GetSystemMenu(hwnd, false);

var cmd = UnsafeNativeMethods.TrackPopupMenuEx(hmenu, Constants.TPM_LEFTBUTTON | Constants.TPM_RETURNCMD,
var cmd = UnsafeNativeMethods.TrackPopupMenuEx(hmenu, Constants.TPM_LEFTBUTTON | Constants.TPM_RETURNCMD,
(int)physicalScreenLocation.X, (int)physicalScreenLocation.Y, hwnd, IntPtr.Zero);
if (0 != cmd)
UnsafeNativeMethods.PostMessage(hwnd, Constants.SYSCOMMAND, new IntPtr(cmd), IntPtr.Zero);
Expand All @@ -1037,10 +1041,10 @@ internal void HandleFlyoutStatusChange(Flyout flyout, IEnumerable<Flyout> visibl
var zIndex = flyout.IsOpen ? Panel.GetZIndex(flyout) + 3 : visibleFlyouts.Count() + 2;

// Note: ShowWindowCommandsOnTop is here for backwards compatibility reasons
//if the the corresponding behavior has the right flag, set the window commands' and icon zIndex to a number that is higher than the flyout's.
//if the the corresponding behavior has the right flag, set the window commands' and icon zIndex to a number that is higher than the flyout's.
if (icon != null)
{
icon.SetValue(Panel.ZIndexProperty,
icon.SetValue(Panel.ZIndexProperty,
this.IconOverlayBehavior.HasFlag(WindowCommandsOverlayBehavior.Flyouts) ? zIndex : 1);
}

Expand Down
22 changes: 16 additions & 6 deletions MahApps.Metro/Styles/Clean/CleanWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -153,26 +153,36 @@
Content="{Binding Flyouts, RelativeSource={RelativeSource TemplatedParent}, Mode=OneWay}"
VerticalAlignment="Stretch" />

<!-- Used to create that overlay effect. Can be used for anything. -->
<!-- Container for inactive dialogs. -->
<Grid Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="5"
Grid.RowSpan="2"
Panel.ZIndex="3"
FocusVisualStyle="{x:Null}"
x:Name="PART_MetroInactiveDialogsContainer" />

<!-- Used to create that overlay effect. Can be used for anything. -->
<Grid Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="5"
Grid.RowSpan="2"
Panel.ZIndex="4"
Focusable="False"
FocusVisualStyle="{x:Null}"
x:Name="PART_OverlayBox"
Background="{DynamicResource BlackColorBrush}"
Opacity="0"
Visibility="Hidden" />

<!-- Container for the active dialog. -->
<Grid Grid.Row="0"
Grid.Column="0"
Grid.ColumnSpan="5"
Grid.RowSpan="2"
Panel.ZIndex="4"
Panel.ZIndex="5"
FocusVisualStyle="{x:Null}"
x:Name="PART_MetroDialogContainer" />
x:Name="PART_MetroActiveDialogContainer" />
</Grid>
</AdornerDecorator>
<Border x:Name="PART_Border"
Expand Down Expand Up @@ -262,7 +272,7 @@
<Style TargetType="{x:Type Controls:MetroWindow}"
BasedOn="{StaticResource {x:Type Controls:MetroWindow}}"
x:Key="CleanWindowStyleKey">

<Setter Property="ShowTitleBar"
Value="True" />
<Setter Property="MinWidth"
Expand All @@ -279,7 +289,7 @@
Value="{DynamicResource CleanWindowButtonStyle}" />
<Setter Property="WindowCloseButtonStyle"
Value="{DynamicResource CleanCloseWindowButtonStyle}" />

</Style>

<Style x:Key="CleanWindowButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource MetroWindowButtonStyle}">
Expand Down Expand Up @@ -312,5 +322,5 @@

</Style.Triggers>
</Style>

</ResourceDictionary>
Loading

0 comments on commit 500d535

Please sign in to comment.