Skip to content

Commit

Permalink
Merge pull request #1943 from ButchersBoy/master
Browse files Browse the repository at this point in the history
add mechanism for easy access of a dialog from a view model
  • Loading branch information
punker76 committed May 29, 2015
2 parents 80dffe5 + 09b134d commit 25ddbbf
Show file tree
Hide file tree
Showing 9 changed files with 342 additions and 4 deletions.
80 changes: 80 additions & 0 deletions MahApps.Metro/Controls/Dialogs/DialogCoordinator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
using System;
using System.Threading.Tasks;
using System.Windows;

namespace MahApps.Metro.Controls.Dialogs
{
public class DialogCoordinator : IDialogCoordinator
{
/// <summary>
/// Gets the default instance if the dialog coordinator, which can be injected into a view model.
/// </summary>
public static readonly DialogCoordinator Instance = new DialogCoordinator();

public Task<string> ShowInputAsync(object context, string title, string message, MetroDialogSettings metroDialogSettings = null)
{
var metroWindow = GetMetroWindow(context);

return metroWindow.ShowInputAsync(title, message, metroDialogSettings);
}

public Task<LoginDialogData> ShowLoginAsync(object context, string title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative, LoginDialogSettings settings = null)
{
var metroWindow = GetMetroWindow(context);

return metroWindow.ShowLoginAsync(title, message, settings);
}

public Task<MessageDialogResult> ShowMessageAsync(object context, string title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative, MetroDialogSettings settings = null)
{
var metroWindow = GetMetroWindow(context);

return metroWindow.ShowMessageAsync(title, message, style, settings);
}

public Task<ProgressDialogController> ShowProgressAsync(object context, string title, string message,
bool isCancelable = false, MetroDialogSettings settings = null)
{
var metroWindow = GetMetroWindow(context);

return metroWindow.ShowProgressAsync(title, message, isCancelable, settings);
}

public Task ShowMetroDialogAsync(object context, BaseMetroDialog dialog,
MetroDialogSettings settings = null)
{
var metroWindow = GetMetroWindow(context);

return metroWindow.ShowMetroDialogAsync(dialog, settings);
}

public Task HideMetroDialogAsync(object context, BaseMetroDialog dialog, MetroDialogSettings settings = null)
{
var metroWindow = GetMetroWindow(context);

return metroWindow.HideMetroDialogAsync(dialog, settings);
}

public Task<TDialog> GetCurrentDialogAsync<TDialog>(object context) where TDialog : BaseMetroDialog
{
var metroWindow = GetMetroWindow(context);

return metroWindow.GetCurrentDialogAsync<TDialog>();
}

private static MetroWindow GetMetroWindow(object context)
{
if (context == null) throw new ArgumentNullException("context");
if (!DialogParticipation.IsRegistered(context))
throw new InvalidOperationException(
"Context is not registered. Consider using DialogParticipation.Register in XAML to bind in the DataContext.");

var association = DialogParticipation.GetAssociation(context);
var metroWindow = Window.GetWindow(association) as MetroWindow;

if (metroWindow == null)
throw new InvalidOperationException("Control is not inside a MetroWindow.");
return metroWindow;
}
}
}
47 changes: 47 additions & 0 deletions MahApps.Metro/Controls/Dialogs/DialogParticipation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using System.Collections.Generic;
using System.Windows;

namespace MahApps.Metro.Controls.Dialogs
{
public static class DialogParticipation
{
private static readonly IDictionary<object, DependencyObject> ContextRegistrationIndex = new Dictionary<object, DependencyObject>();

public static readonly DependencyProperty RegisterProperty = DependencyProperty.RegisterAttached(
"Register", typeof(object), typeof(DialogParticipation), new PropertyMetadata(default(object), RegisterPropertyChangedCallback));

private static void RegisterPropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
{
if (dependencyPropertyChangedEventArgs.OldValue != null)
ContextRegistrationIndex.Remove(dependencyPropertyChangedEventArgs.OldValue);

if (dependencyPropertyChangedEventArgs.NewValue != null)
ContextRegistrationIndex[dependencyPropertyChangedEventArgs.NewValue] = dependencyObject;
}

public static void SetRegister(DependencyObject element, object context)
{
element.SetValue(RegisterProperty, context);
}

public static object GetRegister(DependencyObject element)
{
return element.GetValue(RegisterProperty);
}

internal static bool IsRegistered(object context)
{
if (context == null) throw new ArgumentNullException("context");

return ContextRegistrationIndex.ContainsKey(context);
}

internal static DependencyObject GetAssociation(object context)
{
if (context == null) throw new ArgumentNullException("context");

return ContextRegistrationIndex[context];
}
}
}
86 changes: 86 additions & 0 deletions MahApps.Metro/Controls/Dialogs/IDialogCoordinator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
using System;
using System.Threading.Tasks;

namespace MahApps.Metro.Controls.Dialogs
{
/// <summary>
/// Use the dialog coordinator to help you interfact with dialogs from a view model.
/// </summary>
public interface IDialogCoordinator
{
/// <summary>
/// Shows the input dialog.
/// </summary>
/// <param name="context">Typically this should be the view model, which you register in XAML using <see cref="DialogParticipation.SetRegister"/>.</param>
/// <param name="title">The title of the MessageDialog.</param>
/// <param name="message">The message contained within the MessageDialog.</param>
/// <param name="settings">Optional settings that override the global metro dialog settings.</param>
/// <returns>The text that was entered or null (Nothing in Visual Basic) if the user cancelled the operation.</returns>
Task<string> ShowInputAsync(object context, string title, string message, MetroDialogSettings settings = null);

/// <summary>
/// Creates a LoginDialog inside of the current window.
/// </summary>
/// <param name="context">Typically this should be the view model, which you register in XAML using <see cref="DialogParticipation.SetRegister"/>.</param>
/// <param name="title">The title of the LoginDialog.</param>
/// <param name="message">The message contained within the LoginDialog.</param>
/// <param name="style"></param>
/// <param name="settings">Optional settings that override the global metro dialog settings.</param>
/// <returns>The text that was entered or null (Nothing in Visual Basic) if the user cancelled the operation.</returns>
Task<LoginDialogData> ShowLoginAsync(object context, string title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative, LoginDialogSettings settings = null);

/// <summary>
/// Creates a MessageDialog inside of the current window.
/// </summary>
/// <param name="context">Typically this should be the view model, which you register in XAML using <see cref="DialogParticipation.SetRegister"/>.</param>
/// <param name="title">The title of the MessageDialog.</param>
/// <param name="message">The message contained within the MessageDialog.</param>
/// <param name="style">The type of buttons to use.</param>
/// <param name="settings">Optional settings that override the global metro dialog settings.</param>
/// <returns>A task promising the result of which button was pressed.</returns>
Task<MessageDialogResult> ShowMessageAsync(object context, string title, string message, MessageDialogStyle style = MessageDialogStyle.Affirmative, MetroDialogSettings settings = null);

/// <summary>
/// Creates a ProgressDialog inside of the current window.
/// </summary>
/// <param name="context">Typically this should be the view model, which you register in XAML using <see cref="DialogParticipation.SetRegister"/>.</param>
/// <param name="title">The title of the ProgressDialog.</param>
/// <param name="message">The message within the ProgressDialog.</param>
/// <param name="isCancelable">Determines if the cancel button is visible.</param>
/// <param name="settings">Optional Settings that override the global metro dialog settings.</param>
/// <returns>A task promising the instance of ProgressDialogController for this operation.</returns>
Task<ProgressDialogController> ShowProgressAsync(object context, string title, string message,
bool isCancelable = false, MetroDialogSettings settings = null);

/// <summary>
/// Adds a Metro Dialog instance to the specified window and makes it visible asynchronously.
/// <para>You have to close the resulting dialog yourself with <see cref="HideMetroDialogAsync"/>.</para>
/// </summary>
/// <param name="context">Typically this should be the view model, which you register in XAML using <see cref="DialogParticipation.SetRegister"/>.</param>
/// <param name="dialog">The dialog instance itself.</param>
/// <param name="settings">An optional pre-defined settings instance.</param>
/// <returns>A task representing the operation.</returns>
/// <exception cref="InvalidOperationException">The <paramref name="dialog"/> is already visible in the window.</exception>
Task ShowMetroDialogAsync(object context, BaseMetroDialog dialog,
MetroDialogSettings settings = null);

/// <summary>
/// Hides a visible Metro Dialog instance.
/// </summary>
/// <param name="context">Typically this should be the view model, which you register in XAML using <see cref="DialogParticipation.SetRegister"/>.</param>
/// <param name="dialog">The dialog instance to hide.</param>
/// <param name="settings">An optional pre-defined settings instance.</param>
/// <returns>A task representing the operation.</returns>
/// <exception cref="InvalidOperationException">
/// The <paramref name="dialog"/> is not visible in the window.
/// This happens if <see cref="ShowMetroDialogAsync"/> hasn't been called before.
/// </exception>
Task HideMetroDialogAsync(object context, BaseMetroDialog dialog, MetroDialogSettings settings = null);

/// <summary>
/// Gets the current shown dialog.
/// </summary>
/// <param name="context">Typically this should be the view model, which you register in XAML using <see cref="DialogParticipation.SetRegister"/>.</param>
Task<TDialog> GetCurrentDialogAsync<TDialog>(object context) where TDialog : BaseMetroDialog;
}
}
3 changes: 3 additions & 0 deletions MahApps.Metro/MahApps.Metro.NET45.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,9 @@
<Compile Include="Behaviours\StylizedBehaviorCollection.cs" />
<Compile Include="Behaviours\TabControlSelectFirstVisibleTabBehavior.cs" />
<Compile Include="Behaviours\WindowsSettingBehaviour.cs" />
<Compile Include="Controls\Dialogs\DialogCoordinator.cs" />
<Compile Include="Controls\Dialogs\DialogParticipation.cs" />
<Compile Include="Controls\Dialogs\IDialogCoordinator.cs" />
<Compile Include="Controls\Helper\ButtonHelper.cs" />
<Compile Include="Controls\ClosingWindowEventHandlerArgs.cs" />
<Compile Include="Controls\Helper\ComboBoxHelper.cs" />
Expand Down
3 changes: 3 additions & 0 deletions MahApps.Metro/MahApps.Metro.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,8 @@
<Compile Include="Actions\SetFlyoutOpenAction.cs" />
<Compile Include="Behaviours\BindableResourceBehavior.cs" />
<Compile Include="Behaviours\BorderlessWindowBehavior.cs" />
<Compile Include="Controls\Dialogs\DialogCoordinator.cs" />
<Compile Include="Controls\Dialogs\DialogParticipation.cs" />
<Compile Include="Behaviours\GlowWindowBehavior.cs" />
<Compile Include="Behaviours\PasswordBoxBindingBehavior.cs" />
<Compile Include="Behaviours\StylizedBehaviorCollection.cs" />
Expand All @@ -95,6 +97,7 @@
<Compile Include="Controls\Dialogs\BaseMetroDialog.cs" />
<Compile Include="Controls\Dialogs\DialogManager.cs" />
<Compile Include="Controls\Dialogs\DialogStateChangedEventArgs.cs" />
<Compile Include="Controls\Dialogs\IDialogCoordinator.cs" />
<Compile Include="Controls\Dialogs\InputDialog.cs" />
<Compile Include="Controls\Dialogs\LoginDialog.cs" />
<Compile Include="Controls\Dialogs\ProgressDialog.cs" />
Expand Down
3 changes: 2 additions & 1 deletion samples/MetroDemo/ExampleWindows/FlyoutDemo.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
using System.Windows;
using System.Windows.Input;
using MahApps.Metro.Controls;
using MahApps.Metro.Controls.Dialogs;
using MetroDemo.Models;

namespace MetroDemo.ExampleWindows
Expand All @@ -13,7 +14,7 @@ public partial class FlyoutDemo : IDisposable

public FlyoutDemo()
{
this.DataContext = new MainWindowViewModel();
this.DataContext = new MainWindowViewModel(DialogCoordinator.Instance);
this.InitializeComponent();
this.Closing += (s, e) =>
{
Expand Down
15 changes: 14 additions & 1 deletion samples/MetroDemo/MainWindow.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
d:DesignHeight="600"
d:DesignWidth="800"
d:DataContext="{d:DesignInstance MetroDemo:MainWindowViewModel}"
Closing="MetroWindow_Closing">
Closing="MetroWindow_Closing"
Dialog:DialogParticipation.Register="{Binding}"
>

<Window.Resources>
<ResourceDictionary>
Expand Down Expand Up @@ -178,6 +180,17 @@
Header="Show CustomDialog Externally" />
<MenuItem Click="ShowAwaitCustomDialog"
Header="Await CustomDialog" />
<Separator />
<MenuItem Command="{Binding ShowInputDialogCommand}"
Header="Show InputDialog via VM" />
<MenuItem Command="{Binding ShowLoginDialogCommand}"
Header="Show LoginDialog via VM" />
<MenuItem Command="{Binding ShowMessageDialogCommand}"
Header="Show MessageDialog via VM" />
<MenuItem Command="{Binding ShowProgressDialogCommand}"
Header="Show ProgressDialog via VM" />
<MenuItem Command="{Binding ShowCustomDialogCommand}"
Header="Show CustomDialog via VM" />
</MenuItem>
<MenuItem Header="Window">
<MenuItem IsCheckable="True" Header="ShowInTaskbar"
Expand Down
2 changes: 1 addition & 1 deletion samples/MetroDemo/MainWindow.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public partial class MainWindow

public MainWindow()
{
_viewModel = new MainWindowViewModel();
_viewModel = new MainWindowViewModel(DialogCoordinator.Instance);
DataContext = _viewModel;

InitializeComponent();
Expand Down
Loading

0 comments on commit 25ddbbf

Please sign in to comment.