web-dev-qa-db-ja.com

メインウィンドウを閉じるときにWPFアプリがシャットダウンしない

私はVisual StudioでのWinFormsプログラミングに慣れていますが、WPFを試してみたいと思いました。

プロジェクトにWindow01という別のウィンドウを追加しました。メインウィンドウはMainWindowと呼ばれます。 public MainWindow()コンストラクターの前に、Window01を宣言します。

_Window01 w1;
_

次に、このウィンドウを次の場所でインスタンス化します。

_private void Window_Loaded(object sender, RoutedEventArgs e)
{
    w1 = new Window01();            
}
_

ウィンドウが表示されるボタンw1.ShowDialog();があります。

ここでの「面白い」ことは、アプリケーションを(デバッグを使用して)開始し、数秒後にアプリケーションを終了した場合(アプリケーションで何もしない)、Visual Studioはアプリケーションがまだ実行されています。

w1 = new Window01();をボタンクリックメソッド、つまりShowDialog()のすぐ上に移動すると、Visual Studioは正常に動作します。つまり、アプリケーションを終了するとデバッグが停止します。

なぜこの奇妙な振る舞いですか?

64
eightx2

あなたのMainWindow.xaml.cs、これを試してください:

protected override void OnClosed(EventArgs e)
{
    base.OnClosed(e);

    Application.Current.Shutdown();
}

このリンクごとに、XAMLでShutdownModeを設定することもできます。

http://msdn.Microsoft.com/en-us/library/system.windows.application.shutdownmode.aspx

<Application
    xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
    StartupUri="MainWindow.xaml"
    ShutdownMode="OnExplicitShutdown"
    >
</Application>

アプリケーションは、ShutdownApplicationメソッドが呼び出されたときにのみ実行を停止します。シャットダウンは、ShutdownModeプロパティの値で指定されているように、暗黙的または明示的に発生します。

ShutdownModeOnLastWindowCloseに設定すると、現在インスタンス化されているウィンドウがメインウィンドウとして設定されている場合でも、Windows Presentation Foundation(WPF)はアプリケーションの最後のウィンドウが閉じたときに暗黙的にShutdownを呼び出します(MainWindow )。

ShutdownModeOnMainWindowCloseにより、他のウィンドウが現在開いている場合でも、MainWindowが閉じるとWPFが暗黙的にShutdownを呼び出します。

一部のアプリケーションの有効期間は、メインウィンドウまたは最後のウィンドウがいつ閉じられたかに依存していないか、ウィンドウにまったく依存していない可能性があります。これらのシナリオでは、ShutdownModeプロパティをOnExplicitShutdownに設定する必要があり、アプリケーションを停止するには明示的なShutdownメソッド呼び出しが必要です。それ以外の場合、アプリケーションはバックグラウンドで実行され続けます。

ShutdownModeは、XAMLから宣言的に構成するか、コードからプログラムで構成できます。

このプロパティは、Applicationオブジェクトを作成したスレッドからのみ使用できます。


あなたの場合、おそらくデフォルトのOnLastWindowCloseを使用しているため、アプリは閉じません。

ShutdownModeOnLastWindowCloseに設定すると、現在インスタンス化されているウィンドウがメインウィンドウとして設定されている場合でも、WPFはアプリケーションの最後のウィンドウが閉じるときに暗黙的にShutdownを呼び出します(MainWindow )。

新しいウィンドウを開いており、閉じていないので、シャットダウンは呼び出されません。

117
Bob Horn

回答が得られたことをうれしく思いますが、他の人のために、いくつかの情報を追加するためにあなたの質問にも答えます。


ステップ1

まず、メインウィンドウが閉じたときにプログラムを終了する場合は、この動作がデフォルトのWinFormsではないため、指定する必要があります。

(WPFのデフォルトは、最後のウィンドウが閉じたときです)

コード内

エントリポイントでアプリケーションインスタンスに移動します(VS 2012のWPFプログラムでは、デフォルトはApp.xamlので、insideに行き、App.xaml.cs&コンストラクターを作成します)。

コンストラクターで、 ApplicationShutdownModeShutdownModeであることを指定します .OnLastWindowClose

    public App()
    {
        ShutdownMode = ShutdownMode.OnLastWindowClose;
    }

XAMLで

App.xaml VS 2012がデフォルトで作成した(または自分で作成した)ルートはApplicationであり、 ApplicationShutdownModeShutdownMode .OnLastWindowCloseでなければなりません。

<Application x:Class="WpfApplication27.App"
         xmlns="http://schemas.Microsoft.com/winfx/2006/xaml/presentation"
         xmlns:x="http://schemas.Microsoft.com/winfx/2006/xaml"
         StartupUri="MainWindow.xaml"
         ShutdownMode="OnMainWindowClose">

動作する場合、完了です。読むのをやめることができます。


ステップ2

上記が機能しなかった場合(WPFアプリケーションをゼロから作成したと思います)、メインウィンドウはおそらくアプリケーションにメインウィンドウとして認識されていません。したがって、そのように指定します。

コード内

手順1で行ったようにアプリケーションのコンストラクターに移動し、 ApplicationMainWindow の値があなたの Window

MainWindow = mainWindow;

XAMLで

手順1で行ったようにApplication XAMLに移動し、 ApplicationMainWindow を指定しますの値はあなたの Window です:

MainWindow = "mainWindow";

代替案

WPFがあなたにこれを望んでいないという理由だけで、これが最善のアプローチだとは思いません(したがって、 Application 's ShutdownMode )、ただし、イベントを使用するだけで、イベントメソッドをオーバーライドできます(OnEventHappened)。

MainWindowの分離コードファイルに移動して、以下を追加します。

    protected override void OnClosed(EventArgs e)
    {
        base.OnClosed(e);

        App.Current.Shutdown();
    }
25
MasterMastic

WPFアプリケーションのデフォルトの シャットダウンモード はOnLastWindowCloseであるため、最後のウィンドウが閉じるとアプリケーションが停止します。

新しいWindowオブジェクトをインスタンス化すると、アプリケーションの windowsのリスト に自動的に追加されます。したがって、問題は、アプリケーションが起動時に2つのウィンドウ(MainWindowとまだ表示されていないWindow01)を作成し、MainWindowを閉じただけの場合、Window01がアプリケーションを実行し続けることでした。

通常、ShowDialogを呼び出すのと同じメソッドでウィンドウオブジェクトを作成し、ダイアログが表示されるたびに新しいウィンドウオブジェクトを作成します。

11
Joe Daley

他の何かを探しているときにこの質問に出くわし、Window.Ownerについて言及している提案された回答のどれも見られなかったことに驚きました。

    {
       var newWindow = new AdditionalWindow();
       newWindow.Owner = Window.GetWindow(this);

       // then later on show the window with Show() or ShowDialog()
    }

Window.GetWindow(this)の呼び出しは、MVVMアプリケーションのビューで、インスタンス化された場所がわからないビジュアルツリーをはるかに下回っている場合に非常に便利です。FrameWork要素(たとえばUserContolButtonPage)。明らかに、ウィンドウへの直接参照がある場合は、それまたはApplication.Current.MainWindowを使用します。

これは非常に強力な関係であり、最初は気付かないかもしれない多くの有用な利点があります(これらの関係を回避するために個別のウィンドウを具体的にコーディングしていないと仮定します)。

メインウィンドウをMainWindow、2番目のウィンドウをAdditionalWindowとして呼び出すと、...

  1. MainWindowを最小化すると、AdditionalWindowも最小化されます
  2. MainWindowを復元すると、AdditionalWindowも復元されます
  3. MainWindowを閉じるとAdditionalWindowが閉じますが、AdditionalWindowを閉じてもMainWindowは閉じません。
  4. AdditioanlWindowMainWindowの下で「失われる」ことはありません。つまり、Show()を使用すると、AddditionalWindowは常にzオーダーでMainWindowの上に表示されますそれを表示するには(非常に便利!)

ただし、この関係がある場合、ClosingAdditionalWindowイベントは呼び出されないため、OwnedWindowsコレクションを手動で反復処理する必要があります。 。例えば新しいインターフェイスまたは基本クラスメソッドを介して各ウィンドウを呼び出す方法を作成します。

    private void MainWindow_OnClosing(object sender, CancelEventArgs e)
    {
        foreach (var window in OwnedWindows)
        {
            var win = window as ICanCancelClosing;  // a new interface you have to create
            e.Cancel |= win.DoYouWantToCancelClosing();
        }        
    }
0
Rhys

ダイアログボックスとして機能する2つ目のウィンドウを作成したときに遭遇したように見えます。 2番目のウィンドウを開いてから閉じてからメインウィンドウを閉じても、アプリは(バックグラウンドで)実行を続けました。 App.xamlに以下を追加(または確認)しました。

<Application x:Class="XXXXXXX.App"
             ...  
             StartupUri="MainWindow.xaml"
             ShutdownMode="OnMainWindowClose">
    <Application.MainWindow >
        <NavigationWindow Source="MainWindow.xaml" Visibility="Visible" />
    </Application.MainWindow>

喜びはありません。

そこで、ようやく「MainWindow.xaml」に入り、「Closed」プロパティをWindowに追加し、次のような「MainWind_Closed」メソッドに進みました。

 private void MainWind_Closed(object sender, EventArgs e)
        {
            foreach ( Window w in App.Current.Windows )
            {
                if (w.DataContext != this)
                    w.Close();
            }
        }

デバッガーを実行すると、表示される唯一のウィンドウはダイアログとして作成したウィンドウであるように見えます。つまり、foreachループはメインではなくダイアログを1つだけ検索します。

ダイアログを閉じるメソッドで「this.Close()」を実行していましたが、「dlgwin.ShowDialog()」の後に「dlgwin.Close()」があり、動作しませんでした。 「dlgwin = null」でもありません。

それでは、この余分なものがなければダイアログが閉じないのはなぜですか?しかたがない。これは動作します。

0
Lowell