メインウィンドウを閉じてもWPFアプリがシャットダウンしない


82

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

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

Window01 w1;

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

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

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

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

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

なぜこの奇妙な行動?

回答:


137

あなたの中でMainWindow.xaml.cs、これをやってみてください:

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

    Application.Current.Shutdown();
}

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

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>

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

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

A ShutdownModeofを使用するOnMainWindowCloseと、他のウィンドウが現在開いている場合でも、MainWindowが閉じたときにWPFが暗黙的にShutdownを呼び出します。

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

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

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


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

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

新しいウィンドウを開いているのに閉じていないので、shutdownは呼び出されません。


1
特定のタスクを実行するために他のスレッドをインスタンス化した場合は、オーバーライド機能が最適であることに注意することが重要です。シャットダウンが完了する前に、OnClosed関数でスレッドを停止します。それ以外の場合、スレッドは存続し、アプリは本当に終了しません。
weezma2004 2017年

35

あなたがあなたの答えを受け取ってくれてうれしいですが、他の人のために私はあなたの質問にも答えます-いくつかの情報を追加します。


ステップ1

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

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

コード内

エントリポイントのアプリケーションインスタンスに移動します(VS 2012のWPFプログラムでは、デフォルトは内部App.xamlにネストされているため、内部に移動しApp.xaml.csてコンストラクターに移動して作成します)。

コンストラクタでは、あなたのように指定するApplicationのがShutdownModeあるべきShutdownModeOnLastWindowClose

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

XAMLの場合

App.xamlVS 2012がデフォルトで作成したファイルに移動します(または自分で作成します)。ルートはApplicationです。ApplicationさんがShutdownModeでなければなりませんShutdownModeOnLastWindowClose

<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で行ったようにアプリケーションのコンストラクターに移動し、それを指定しApplicationます。MainWindowの価値はあなたですWindowです:

MainWindow = mainWindow;

XAMLの場合

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

MainWindow = "mainWindow";

代替案

それは持っているので、私は(WPFは、あなたがこれを行うにはしたくありませんという理由だけで、これが最善の方法だとは思いませんApplicationShutdownMode)、あなただけのイベントメソッド(OnEventHappened)をオーバーライド/イベントを使用することができます。

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

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

        App.Current.Shutdown();
    }

3
あなたの答えは、マークされているものよりも優れています。
シーカー2016

私は通常、次のようにします。MainWindowメインウィンドウのインスタンスに設定ShutdownModeShutdownMode.OnMainWindowClose、に設定し、のイベントMainWindow.Show()へのコールバックを呼び出します。これは、少なくともWPFを使用する.NET Core 3で期待どおりに機能する、私が思いついた最小のソリューションです。StartupApp
TorbenJ

11

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

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

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


2

私は何か他のものを探しているときにこの質問に出くわしました、そして私はについて言及している提案された答えのどれも見ることができなかったことに驚きました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に「失われる」ことはありません。つまり、以前に表示していた場合はAddditionalWindow常に上MainWindowにzオーダーでShow()表示されます(非常に便利です!)

ただし、この関係がある場合は、上のClosingイベントAdditionalWindowが呼び出されないため、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();
        }        
    }

1

おそらく私たちのプロジェクトがPrismを使用しているため、上記のどれも私にはうまくいきませんでした。そのため、App.XAML.csでこれを使用することになりました

    protected override void OnExit(ExitEventArgs e)
    {
        base.OnExit(e);
        Process.GetCurrentProcess().Kill();
    }

0

ダイアログボックスとして機能する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」プロパティをウィンドウに追加して、次のような「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」でさえありません。

では、なぜこの余分なものなしでそのダイアログが閉じないのでしょうか?しかたがない。これは機能します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.