Posted at

PopupWindowActionのコンテンツ指定方法WindowContentとWindowContentTypeで挙動が異なる


結論


WindowContent

PopupWindowActionを記述したviewが生成されたタイミングでWindowContentで指定したView(紐づいているViewModelも)も生成される。

PopupWindowActionを何回実行してもWindowContentで指定したViewは再生成されずインスタンスが使い回される。


WindowContentType

PopupWindowActionを実行するたび新しくWindowContentTypeで指定したView(紐づいているViewModelも)が生成される。


動機

PRISMのサンプルを参照してPopupWindowActionを実装していたんですけど、WindowContent指定の方法しか載っていなくて、↑の挙動をしていてカスタムウィンドウの場合だと使いづらいなあと思っていたので調査しました。


調査内容

PopupWindowActionを見ればわかりました。


PopupWindowAction抜粋

        /// <summary>

/// The content of the child window to display as part of the popup.
/// </summary>
public static readonly DependencyProperty WindowContentProperty =
DependencyProperty.Register(
"WindowContent",
typeof(FrameworkElement),
typeof(PopupWindowAction),
new PropertyMetadata(null));

/// <summary>
/// The type of content of the child window to display as part of the popup.
/// </summary>
public static readonly DependencyProperty WindowContentTypeProperty =
DependencyProperty.Register(
"WindowContentType",
typeof(Type),
typeof(PopupWindowAction),
new PropertyMetadata(null));

/// <summary>
/// Checks if the WindowContent or its DataContext implements <see cref="IInteractionRequestAware"/>.
/// If so, it sets the corresponding values.
/// </summary>
/// <param name="notification">The notification to be set as a DataContext in the HostWindow.</param>
/// <param name="wrapperWindow">The HostWindow</param>
protected virtual void PrepareContentForWindow(INotification notification, Window wrapperWindow)
{
if (this.WindowContent != null)
{
// We set the WindowContent as the content of the window.
wrapperWindow.Content = this.WindowContent;
}
else if (this.WindowContentType != null)
{
wrapperWindow.Content = ServiceLocator.Current.GetInstance(this.WindowContentType);
}
else
{
return;
}

Action<IInteractionRequestAware> setNotificationAndClose = (iira) =>
{
iira.Notification = notification;
iira.FinishInteraction = () => wrapperWindow.Close();
};

MvvmHelpers.ViewAndViewModelAction(wrapperWindow.Content, setNotificationAndClose);
}


ソースの通りWindowContent添付プロパティ以外にWindowContentType添付プロパティが定義されていて、両方定義されていた場合はWindowContentが優先されます。

WindowContentの場合はWindowContentで指定したインスタンスがそのまま設定されますが

WindowContentTypeの場合はコンテナから取得して設定されます。

なのでWindowContentTypeの場合の生成方法はコンテナ登録時の指定によりますがRegisterForNavigationで指定する分には都度生成でした。


App.xaml.cs抜粋

        protected override void RegisterTypes(IContainerRegistry containerRegistry)

{
containerRegistry.RegisterForNavigation<~~View>();
}


WindowContentとWindowContentTypeの指定例


WindowContent

            <prism:PopupWindowAction>

<prism:PopupWindowAction.WindowContent>
<local:~~~View />
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>


WindowContentType

            <prism:PopupWindowAction WindowContentType="{x:Type local:~~~View}">

</prism:PopupWindowAction>


まとめ

通知や確認などの簡単なウィンドウならWindowContetで指定して、カスタムウィンドウでゴリゴリやりたいならWindowContentType指定が良いかと思いました。