none
ウィンドウを重複起動させない方法 RRS feed

  • 質問

  • ウィンドウをモードレスでかならず1つだけしか表示させない良い方法を探しております。

    例えば、以下のコードのようにボタンを押すと
    モードレスで別のウィンドウが立ち上がるようにしています。

    Private Sub Button1_Click(sender As System.Object, e As System.Windows.RoutedEventArgs) Handles Button1.Click
    
        Dim w = New SubWindow()
        w.Show()
    
    End Sub
    

    しかし、これではボタンを押す度にSubWindowが開いてしまいます。
    すでにSubWindowが開いているときは新しいウィンドウを開かないようにしたいです。

    方法として次の3通りを考えました。

    1.Application.Current.WindowsをFor文でまわしてすでにインスタンスが存在していないかどうか調べる
    2.SubWindowのインスタンスを管理するためのフィールドをMainWindowに準備する
    3.SubWindowクラスをシングルトンで設計し、呼び出し用の共有メソッドshowを作る

    1は最もシンプルですが、VB6以前ではSubWindow.showで要件を満たすことができただけに
    .netの方が新しいのになんだかなと思ってしまいます。
    ※ちなみにVB6のSubWindow.Showのように使用する方法として、
    My.Windows.SubWindow.Show()ということ方法でウィンドウの重複起動しないようにすることが可能のようですが
    実際ためしてみるとMy.Windows.SubWindow.Show()はSubWindowを閉じたあともう一度呼ぶと
    エラーが発生してしまいました。

    2はウィンドウの種類を増やす度にMainWindowが管理するフィールドが増えていくので
    あまり良い方法とは思えません。

    3はSubWindowを利用する側は便利ですが、SubWindowを作る側の手間が若干増えてしまうのが懸念です。

    モードレスのウィンドウを1つだけ表示したいとき、
    みなさんはどのような方法を用いておられるのでしょうか。
    よろしくお願い致します


    2013年1月20日 16:49

回答

  • Window クラスがそのように実装されているため、同じインスタンスを使い回すことはできません。
    従って、My.Windows.SubWindow.Show() では、閉じた後に呼び出すと例外が発生します。
    VB6 の頃と使い勝手が微妙だと言われても、Form(Window) の実装が違うので仕方がありません。(Form(Window) は VB だけでなく、C# などでも共通の実装であるため、VB.NET だけが別の動きをすることはできません)

    クラスごと、表示箇所ごとに実装するのが面倒だというのであれば、1 の実装をヘルパーメソッドとしてどこかに作ればよいでしょう。
    以下はその一例ですが、LINQ を使っていることと、弱点があるかどうかをきちんと検証していないことと、ほかによりよい方法があるかどうか判断できていないことがあるのでご留意ください。

    Public Class WindowHelper
        Public Shared Sub ShowWindow(Of T As {Window, New})()
            If Application.Current.Windows.OfType(Of T).Any() Then Exit Sub
            Dim w As New T()
            w.Show()
        End Sub
    End Class
    • 編集済み AzuleanMVP 2013年1月20日 21:57
    • 回答の候補に設定 佐伯玲 2013年1月21日 4:19
    • 回答としてマーク 佐伯玲 2013年1月28日 2:34
    2013年1月20日 21:55

すべての返信

  • Window クラスがそのように実装されているため、同じインスタンスを使い回すことはできません。
    従って、My.Windows.SubWindow.Show() では、閉じた後に呼び出すと例外が発生します。
    VB6 の頃と使い勝手が微妙だと言われても、Form(Window) の実装が違うので仕方がありません。(Form(Window) は VB だけでなく、C# などでも共通の実装であるため、VB.NET だけが別の動きをすることはできません)

    クラスごと、表示箇所ごとに実装するのが面倒だというのであれば、1 の実装をヘルパーメソッドとしてどこかに作ればよいでしょう。
    以下はその一例ですが、LINQ を使っていることと、弱点があるかどうかをきちんと検証していないことと、ほかによりよい方法があるかどうか判断できていないことがあるのでご留意ください。

    Public Class WindowHelper
        Public Shared Sub ShowWindow(Of T As {Window, New})()
            If Application.Current.Windows.OfType(Of T).Any() Then Exit Sub
            Dim w As New T()
            w.Show()
        End Sub
    End Class
    • 編集済み AzuleanMVP 2013年1月20日 21:57
    • 回答の候補に設定 佐伯玲 2013年1月21日 4:19
    • 回答としてマーク 佐伯玲 2013年1月28日 2:34
    2013年1月20日 21:55
  • こんにちは、ひょうじめいx さん
    フォーラムオペレータの佐伯 玲 です。

    その後Azulean さんからの情報はご確認いただけたでしょうか?
    参考になる情報だと思われたので勝手ながら私のほうで「回答としてマーク」とさせて頂きました。

    一旦「回答としてマーク」をさせてはいただきましたが寄せられた情報をお試しいただき進展がございましたら引き続きこちらのスレッドへご返信くださいませ。

    宜しくお願いいたします。
    __________________________
    日本マイクロソフト株式会社 フォーラム オペレータ 佐伯 玲

    2013年1月28日 2:34