はじめに
Prism.Wpfでダイアログを出す時、
<i:Interaction.Triggers>
<prism:InteractionRequestTrigger SourceObject="{Binding Hoge}">
<prism:PopupWindowAction/>
</prism:InteractionRequestTrigger>
<i:Interaction.Triggers>
Viewにこんな感じでInteractionRequestTriggerを定義して、ViewModelの表示させたい処理でInteractionRequestをRaiseすると思う
普通に使う分には何の問題もないのだが、このダイアログをMahApps.MetroのMetroWindowにしようとするといい方法が見つからない
MetroWindowをだせるものを作った
2019/03/18 更新
Prism v7.1以降ではPopupWindowAction
のCreateDefaultWindow()
がvirtualに変更されているため、PopupWindowAction
クラスを継承してoverrideするだけでよくなった
また、v7.2-preではIDialogService
という新たなダイアログ表示機能が用意されたので、正式にリリースされればこちらを使用するようになると思う
使い方を記事にしてくれている方がいたのでリンクを貼っておく
Prism7.2(pre)の新機能 IDialogServiceを試してみた
できたもの
Prism.Interactivity.MahAppsPack
public class PopupMetroWindowAction : PopupWindowAction
{
#region MetroStyle
public ResourceDictionary MetroStyle
{
get { return (ResourceDictionary)GetValue(MetroStyleProperty); }
set { SetValue(MetroStyleProperty, value); }
}
public static readonly DependencyProperty MetroStyleProperty =
DependencyProperty.Register("MetroStyle", typeof(ResourceDictionary), typeof(PopupMetroWindowAction), new PropertyMetadata(null));
#endregion
#region Accent
public Accents? Accent
{
get { return (Accents?)GetValue(AccentProperty); }
set { SetValue(AccentProperty, value); }
}
public static readonly DependencyProperty AccentProperty =
DependencyProperty.Register("Accent", typeof(Accents?), typeof(PopupMetroWindowAction), new PropertyMetadata(null));
#endregion
#region Theme
public Themes? Theme
{
get { return (Themes?)GetValue(ThemeProperty); }
set { SetValue(ThemeProperty, value); }
}
public static readonly DependencyProperty ThemeProperty =
DependencyProperty.Register("Theme", typeof(Themes?), typeof(PopupMetroWindowAction), new PropertyMetadata(null));
#endregion
protected override Window CreateWindow()
{
MetroWindow window = new DefaultMetroWindow();
this.SetMetroStyle(window);
return window;
}
protected override Window CreateDefaultWindow(INotification notification)
{
MetroWindow window = null;
if (notification is IConfirmation) window = new DefaultConfirmationMetroWindow() { Confirmation = (IConfirmation)notification };
else window = new DefaultNotificationMetroWindow() { Notification = notification };
this.SetMetroStyle(window);
return window;
}
/// <summary>
/// <see cref="MetroWindow"/>にMetroStyle(AccentとTheme)をセットする
/// <para>MetroStyleが設定されていれば最優先で適用される</para>
/// <para>MetroStyleが設定されておらず、AccentとThemeが設定されていればこれらを適用する</para>
/// <para>MetroStyleが設定されておらず、AccentとThemeの両方が設定されていなければOwnerと同じものを適用する</para>
/// </summary>
/// <param name="window"></param>
protected virtual void SetMetroStyle(MetroWindow window)
{
if (window == null) return;
if (this.MetroStyle != null)
{
window.Resources.MergedDictionaries.Add(this.MetroStyle);
return;
}
if (this.Accent.HasValue && this.Theme.HasValue)
{
MahApps.Metro.ThemeManager.ChangeAppStyle(
window,
MahApps.Metro.ThemeManager.GetAccent(AccentsExtensions.ToStringFromEnum(this.Accent.Value)),
MahApps.Metro.ThemeManager.GetAppTheme(ThemesExtensions.ToStringFromEnum(this.Theme.Value)));
return;
}
window.Owner = Window.GetWindow(this.AssociatedObject);
if (window.Owner is MetroWindow)
{
window.Resources.MergedDictionaries.AddRange(window.Owner.Resources.MergedDictionaries);
}
}
}
CreateWindow()
とCreateDefaultWindow()
をoverrideし、PrismのDefaultPopupWindowsと同様の適切なMetroWindowを生成してSetMetroStyle()
を呼んでいる
SetMetroStyle()
ではMetroWindowにStyle(Accent,Theme)を適用している
MetroStyle,Accent,Themeはそれぞれ依存関係プロパティで定義し、xaml側から指定できるようにしている
MetroStyleは、直接ResourceDictionaryを記述するのもOKだが、別ファイルに
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<ResourceDictionary.MergedDictionaries>
<!--MahApps.Metro resource dictionaries. Make sure that all file names are Case Sensitive!-->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Controls.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Fonts.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/FlatButton.xaml" />
<!--Accent and AppTheme setting-->
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/Red.xaml" />
<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseLight.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
こんな感じでMahApps.Metroのスタイルを定義してResourceDictionaryのSourceプロパティにこのファイルを指定するほうがいいと思う
また、ダイアログの呼び出し元のWindowがMetroWindowで、これらのプロパティを指定していない場合は呼び出し元と同じStyleを適用するようにしている
使い方
リポジトリの中にサンプルもいれている
Prism.Interactivity.MahAppsPack/Prism.Interactivity.MahAppsPack-Samples/
以下、主要部分抜粋
<i:Interaction.Triggers>
<!--Metro-->
<prism:InteractionRequestTrigger SourceObject="{Binding MetroNotification}">
<prismMetro:PopupMetroWindowAction
WindowStartupLocation="CenterOwner"
IsModal="True"/>
</prism:InteractionRequestTrigger>
<prism:InteractionRequestTrigger SourceObject="{Binding MetroConfirmation}">
<prismMetro:PopupMetroWindowAction
CenterOverAssociatedObject="True"
IsModal="True"/>
</prism:InteractionRequestTrigger>
<prism:InteractionRequestTrigger SourceObject="{Binding MetroWindowNotification}">
<prismMetro:PopupMetroWindowAction
CenterOverAssociatedObject="True"
IsModal="True">
<prismMetro:PopupMetroWindowAction.MetroStyle>
<ResourceDictionary Source="/Prism.Interactivity.MahAppsPack-Samples;component/MetroWindowStyle.xaml"/>
</prismMetro:PopupMetroWindowAction.MetroStyle>
<prismMetro:PopupMetroWindowAction.WindowContent>
<local:SubWindow/>
</prismMetro:PopupMetroWindowAction.WindowContent>
</prismMetro:PopupMetroWindowAction>
</prism:InteractionRequestTrigger>
</i:Interaction.Triggers>
<i:Interaction.Triggers>
<prism:InteractionRequestTrigger SourceObject="{Binding Notification}">
<!--指定したAccentとThemeを適用-->
<prismMetro:PopupMetroWindowAction
CenterOverAssociatedObject="True"
Accent="{Binding Accent.Value}"
Theme="{Binding Theme.Value}"/>
</prism:InteractionRequestTrigger>
<prism:InteractionRequestTrigger SourceObject="{Binding Confirmation}">
<!--OwnerのAccentとThemeを適用-->
<prismMetro:PopupMetroWindowAction
CenterOverAssociatedObject="True"/>
</prism:InteractionRequestTrigger>
</i:Interaction.Triggers>
CustomContent
PopupWindowActionを継承しているため、当然IInteractionRequestAware
を実装して独自のContentを表示することもできる
使い方は以下参照
PrismEdu/05.InteractionRequest/
おわりに
個人的にやりたかったことができたので満足
おかしい点や他にいいやり方があれば教えて下さい(人∀・)