Ana Pencereyi Kapatırken WPF Uygulaması Kapanmıyor


82

Visual Studio'da WinForms programlamaya alışkınım, ancak WPF'yi denemek istedim.

Projeme Window01 adında başka bir pencere ekledim. Ana pencereye MainWindow denir. public MainWindow()Yapıcıdan önce Window01'i beyan ederim:

Window01 w1;

Şimdi bu pencereyi şurada başlatıyorum:

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

Ben pencere gösterilir bir düğme vardır: w1.ShowDialog();.

Buradaki 'komik' şey, uygulamayı başlatırsam (hata ayıklama ile) ve birkaç saniye sonra çıkarsam (uygulamada hiçbir şey yapmazsam), Visual Studio'nun uygulama açık gibi hata ayıklamayı durdurmamasıdır. hala koşuyor.

Satırı w1 = new Window01();düğme tıklama yöntemine taşırsam, yani hemen yukarıda ShowDialog(), Visual Studio düzgün davranıyor - yani uygulamadan çıktığımda hata ayıklama durur.

Neden bu garip davranış?

Yanıtlar:


138

Gözlerinde farklı MainWindow.xaml.cs, bunu deneyin:

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

    Application.Current.Shutdown();
}

Bu bağlantı başına ShutdownMode, XAML'de de ayarlayabilirsiniz :

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>

Uygulamalar, yalnızca Shutdownyöntemi Applicationçağrıldığında çalışmayı durdurur . Kapatma, ShutdownModeözelliğin değeriyle belirtildiği gibi örtük veya açık bir şekilde gerçekleşebilir .

Eğer ayarlarsanız ShutdownModeiçin OnLastWindowCloseherhangi halen örneği pencereler ana pencere olarak ayarlanmış olsa bile, bir uygulama kapanmadan son pencere, (MainWindow bakınız) zaman Windows Presentation Foundation (WPF) örtülü Kapatma çağırır.

Bir ShutdownModeait OnMainWindowClosenedenleri MainWindow kapanır, diğer pencereler şu anda açık olsa bile zaman örtük Kapatma çağırmak wpf.

Bazı uygulamaların ömrü, ana pencerenin veya son pencerenin ne zaman kapatıldığına bağlı olmayabilir veya pencerelere hiç bağlı olmayabilir. Bu senaryolar ShutdownModeiçin OnExplicitShutdown, Shutdownuygulamayı durdurmak için açık bir yöntem çağrısı gerektiren özelliği olarak ayarlamanız gerekir . Aksi takdirde uygulama arka planda çalışmaya devam eder.

ShutdownMode XAML'den bildirimli olarak veya koddan programlı olarak yapılandırılabilir.

Bu özellik yalnızca Applicationnesneyi oluşturan iş parçacığından kullanılabilir .


Sizin durumunuzda, muhtemelen varsayılanı kullandığınız için uygulama kapanmıyor OnLastWindowClose:

Eğer ayarlarsanız ShutdownModeiçin OnLastWindowCloseherhangi halen örneği pencereler ana pencere olarak ayarlanmış olsa bile, bir uygulama kapanmadan son pencere, (görünce, WPF örtülü Kapatma çağırır MainWindow).

Yeni bir pencere açtığınız ve kapatmadığınız için, kapatma çağrılmaz.


1
Belirli görevleri gerçekleştirmek için başka herhangi bir İş Parçacığı örneğini oluşturduysanız, geçersiz kılma işlevinin en iyisi olduğuna dikkat etmek önemlidir. Kapatma işlemi tamamlanmadan önce OnClosed fonksiyonundaki Konuları durdurun. Aksi takdirde, Threads hayatta kalır ve uygulama asla gerçekten çıkmaz.
weezma2004

Sadece MainWindow kapalı olduğu için bir uygulamayı kapatmak iyi bir fikir mi emin değilim. Ayrıca, bu arka plan işleminin DB'ye kaydetme, günlüklere yazma, bir şeyleri önbelleğe alma, cihazların bağlantısını kesme vb. Gibi bir şey yapmaya çalışması da mümkündür ... Bu noktada, uygulamayı kapatan ve düzelten sorunu bulabilirim. Uygulamalarınızın yaşam döngüsünü daima düzenleyin. Application.Current.Shutdown()İşlemi Görev Çubuğunda tamamlar gibi uygulamayı hemen kapatır. Bu, son sözünü söylemeden önce birini vurmak gibidir :) .. Tavsiye etmem.
Vural

35

Cevabını aldığına sevindim, ancak başkalarının iyiliği için sorunuzu cevaplayarak bazı bilgiler ekleyeceğim.


Aşama 1

İlk olarak, ana pencere kapandığında programınızın çıkmasını istiyorsanız, bu davranışın varsayılan olduğu WinForms olmadığından bunu belirtmeniz gerekir.

(WPF'de varsayılan, son pencerenin kapanmasıdır)

Kodda

Giriş noktanızdaki uygulama örneğinize gidin (VS 2012'nin WPF programında varsayılan, iç içe yerleştirilmiştir App.xaml, bu nedenle içine gidin ve bir kurucuya gidin App.xaml.csve oluşturun).

Yapıcıda senin belirtmek Application'ın ShutdownModeolmalıdır ShutdownMode. OnLastWindowClose.

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

XAML'de

Senin git App.xamlkök bir VS 2012 varsayılan olarak oluşturulur o dosyanın (veya kendiniz oluşturun) Application, sizin içerde belirtmek Application'ın ShutdownModeolmalıdır ShutdownMode. 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">

Eğer işe yararsa, bitirdiniz; okumayı bırakabilirsin.


Adım 2

Yukarıdakiler işe yaramadıysa (sanırım WPF uygulamasını sıfırdan yazdınız), ana pencere muhtemelen uygulama tarafından ana pencere olarak bilinmemektedir. Öyleyse bunu da belirtin.

Kodda

Adım 1'de yaptığınız gibi uygulamanın yapıcısına gidin ve bunu belirtin Application. MainWindowdeğeriniz Window:

MainWindow = mainWindow;

XAML'de

ApplicationAdım 1'de yaptığınız gibi XAML'ye gidin ve bunu belirtin Application. MainWindowdeğeriniz Window:

MainWindow = "mainWindow";

Alternatif

Bunun en iyi yaklaşım olduğunu sanmıyorum, çünkü WPF bunu yapmanızı istemiyor (bu yüzden Application'ler var ShutdownMode), ancak sadece bir olay kullanabilir / bir olay yöntemini geçersiz kılabilirsiniz (OnEventHappened).

MainWindow'un arka plan kod dosyasına gidin ve şunu ekleyin:

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

        App.Current.Shutdown();
    }

3
Cevabınız işaretli olandan daha iyidir.
Seekeer

Genellikle bu şekilde yapın: Set MainWindowset ana pencerenin örneğine için ShutdownModeiçin ShutdownMode.OnMainWindowCloseçağrı MainWindow.Show()için geri aramasında Startupdurumunda App. Bu, en azından WPF ile .NET Core 3'te beklendiği gibi çalışan, bulduğum en minimal çözüm.
TorbenJ

11

Bir WPF uygulamasındaki varsayılan kapatma modu OnLastWindowClose olduğundan, bu da uygulamanın son pencere kapandığında durduğu anlamına gelir.

Yeni bir Pencere nesnesi oluşturduğunuzda, otomatik olarak uygulamadaki pencere listesine eklenir . Dolayısıyla, sorun, uygulamanız başladığında iki pencere oluşturmasıydı - MainWindow ve henüz gösterilmemiş Window01 - ve yalnızca MainWindow'u kapatırsanız, Window01 uygulamanızı çalışır durumda tutacaktı.

Normalde, ShowDialog'u çağıracak olan aynı yöntemde bir pencere nesnesi oluşturacaksınız ve iletişim kutusu her gösterildiğinde yeni bir pencere nesnesi oluşturacaksınız.


2

Başka bir şey ararken bu Soruya rastladım ve önerilen cevapların hiçbirinin bahsettiğini göremediğime şaşırdım Window.Owner.

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

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

Bir çağrı Window.GetWindow(this)senin uzağa örneklerle desteklendi nereye bilmeden görsel ağacının aşağı, herhangi sağlayarak çağrılabilir olduğunda bir MVVM uygulama görünümünde oldukça yararlıdır FrameWorkelemanı (örneğin UserContol, Button, Page). Açıkçası, pencereye doğrudan bir referansınız varsa, onu veya hatta kullanın Application.Current.MainWindow.

Bu, başlangıçta fark edemeyeceğiniz bir dizi yararlı faydaya sahip oldukça güçlü bir ilişkidir (bu ilişkilerden kaçınmak için özel olarak ayrı pencereler kodlamadığınızı varsayarak).

Ana pencerenizi MainWindowve ikinci pencerenizi AdditionalWindowo zaman ararsak ...

  1. Azaltmak, MainWindowiradeyi de küçültmekAdditionalWindow
  2. Geri yükleme MainWindowayrıca geri yükleyecektirAdditionalWindow
  3. Kapanış MainWindowyakın olacak AdditionalWindow, ancak kapanış AdditionalWindowyakın olmayacakMainWindow
  4. AdditioanlWindowaltında asla "kaybolmaz" MainWindow, yani AddditionalWindowher zaman yukarıda MainWindowz-sırasına göre gösterilir (eğer daha önce Show()gösterdiyseniz)

Yine de dikkat edilmesi gereken bir şey, eğer bu ilişkiye sahipseniz, Closingüzerindeki olay AdditionalWindowçağrılmaz, bu yüzden OwnedWindowskoleksiyon üzerinde manuel olarak yinelemeniz gerekir . Örneğin, her pencereyi yeni bir Arayüz veya temel sınıf yöntemi aracılığıyla çağırmanın bir yolunu oluşturun.

    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

Yukarıdakilerin hiçbiri benim için işe yaramadı, belki de projemiz Prism kullandığından. Böylece bunu App.XAML.cs dosyasında kullanmaya başladım.

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

0

Bir iletişim kutusu görevi görecek ikinci bir pencere oluşturduğumda karşılaştığım bir şeye benziyor. İkinci pencere açılıp kapatıldığında ve ardından ana pencere kapatıldığında, uygulama çalışmaya devam etti (arka planda). Aşağıdakileri App.xaml dosyama ekledim (veya onayladım):

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

Neşe yok.

Böylece, sonunda "MainWindow.xaml" dosyama girdim ve Pencereye, aşağıdakine benzer bir "MainWind_Closed" yöntemine giden "Closed" özelliğini ekledim:

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

Hata ayıklayıcıdan geçerken, görünen tek pencere bir iletişim kutusu olarak oluşturduğum pencere gibi görünüyor - başka bir deyişle, foreach döngüsü yalnızca bir pencere buluyor - iletişim kutusu, ana değil.

İletişim kutusunu kapatan yöntemde "this.Close ()" çalışıyordu ve "dlgwin.ShowDialog ()" dan sonra gelen bir "dlgwin.Close ()" vardı ve bu işe yaramadı. "Dlgwin = null" bile değil.

Öyleyse, bu ekstra şeyler olmadan bu diyalog neden kapanmasın? Oh iyi. Bu çalışıyor.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.