I am building a Metro-themed WPF application with MVVM approach using Prism and MahApps.Metro. I have to show a custom dialog from view model. Currently, I am using InteractionRequest
and a custom TriggerAction
to accomplish it, but I don't know if this is a good way.
MainWindow.xaml
<Controls:MetroWindow
x:Class="Dialog.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:prism="http://www.codeplex.com/prism"
xmlns:Controls="http://metro.mahapps.com/winfx/xaml/controls"
xmlns:Dialog="clr-namespace:MahApps.Metro.Controls.Dialogs;assembly=MahApps.Metro"
xmlns:local="clr-namespace:Dialog"
AllowsTransparency="False"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<Dialog:CustomDialog Title="MyTitle" x:Key="MyDialog">
<Button Content="Close" Command="{Binding CloseCommand}"/>
</Dialog:CustomDialog>
</ResourceDictionary>
</Window.Resources>
<i:Interaction.Triggers>
<prism:InteractionRequestTrigger SourceObject="{Binding ShowDialogRequest, Mode=OneWay}">
<local:ShowDialogAction DataContext="{Binding DialogViewModel}" DialogKey="MyDialog"/>
</prism:InteractionRequestTrigger>
</i:Interaction.Triggers>
...
</Controls:MetroWindow>
ShowDialogAction
public class ShowDialogAction : TriggerAction<MetroWindow>
{
public static readonly DependencyProperty DataContextProperty =
DependencyProperty.Register(
"DataContext",
typeof(object),
typeof(ShowDialogAction),
new PropertyMetadata(null));
public static readonly DependencyProperty DialogKeyProperty =
DependencyProperty.Register(
"DialogKey",
typeof(string),
typeof(ShowDialogAction),
new PropertyMetadata(null));
public object DataContext
{
get { return this.GetValue(DataContextProperty); }
set { this.SetValue(DataContextProperty, value); }
}
public string DialogKey
{
get { return (string)this.GetValue(DialogKeyProperty); }
set { this.SetValue(DialogKeyProperty, value); }
}
protected async override void Invoke(object parameter)
{
InteractionRequestedEventArgs args = parameter as InteractionRequestedEventArgs;
if (args == null)
{
return;
}
BaseMetroDialog dialog = AssociatedObject.Resources[DialogKey] as BaseMetroDialog;
if (dialog == null)
{
return;
}
dialog.DataContext = DataContext;
IInteractionRequestAware interactionAware = DataContext as IInteractionRequestAware;
if(interactionAware != null)
{
interactionAware.Notification = args.Context;
interactionAware.FinishInteraction = () =>
{
if (AssociatedObject.Dispatcher.CheckAccess())
{
AssociatedObject.HideMetroDialogAsync(dialog);
}
else
{
AssociatedObject.Dispatcher.Invoke(async () => await AssociatedObject.HideMetroDialogAsync(dialog));
}
};
}
await AssociatedObject.ShowMetroDialogAsync(dialog);
}
DialogViewModel
public class DialogViewModel : BindableBase, IInteractionRequestAware
{
public Action FinishInteraction { get; set; }
public INotification Notification { get; set; }
private ICommand closeCommand;
public ICommand CloseCommand
{
get
{
return this.closeCommand ?? (this.closeCommand = new DelegateCommand(FinishInteraction));
}
}
}
I have several questions:
- Which is better, using a resource key or explicitly setting a
Dialog
property forShowDialogAction
accepting aCustomDialog
? - Is there any better alternatives to pass/create a
DialogViewModel
to the dialog? - Is the
FinishInteraction
okay? I am not too familiar with async/await.