Ứng dụng WPF không tắt khi đóng cửa sổ chính


82

Tôi đã quen với việc lập trình WinForms trong Visual Studio, nhưng tôi muốn dùng thử WPF.

Tôi đã thêm một cửa sổ khác vào dự án của mình, được gọi là Window01. Cửa sổ chính được gọi là MainWindow. Trước hàm public MainWindow()tạo, tôi khai báo Window01:

Window01 w1;

Bây giờ tôi khởi tạo cửa sổ này trong:

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

Tôi có một nút nơi cửa sổ được hiển thị: w1.ShowDialog();.

Điều 'buồn cười' ở đây là thực tế là nếu tôi khởi động ứng dụng (với gỡ lỗi) và thoát khỏi ứng dụng đó vài giây sau đó (tôi không làm gì trong ứng dụng), Visual Studio không ngừng gỡ lỗi như thể ứng dụng vẫn chạy.

Nếu tôi di chuyển dòng w1 = new Window01();sang phương pháp nhấp vào nút, nghĩa là ngay phía trên ShowDialog(), Visual Studio đang hoạt động bình thường - nghĩa là, việc gỡ lỗi sẽ dừng khi tôi thoát ứng dụng.

Tại sao có hành vi kỳ lạ này?

Câu trả lời:


137

Trong của bạn MainWindow.xaml.cs, hãy thử làm điều này:

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

    Application.Current.Shutdown();
}

Theo liên kết này, bạn cũng có thể đặt ShutdownModetrong 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>

Các ứng dụng chỉ ngừng chạy khi Shutdownphương thức của Applicationđược gọi. Việc tắt có thể diễn ra ngầm hoặc rõ ràng, như được chỉ định bởi giá trị của thuộc ShutdownModetính.

Nếu bạn đặt ShutdownModethành OnLastWindowClose, Windows Presentation Foundation (WPF) gọi ngầm là Shutdown khi cửa sổ cuối cùng trong một ứng dụng đóng, ngay cả khi bất kỳ cửa sổ nào hiện được khởi tạo được đặt làm cửa sổ chính (xem MainWindow).

Một ShutdownModetrong những OnMainWindowClosenguyên nhân khiến WPF gọi ngầm là Shutdown khi MainWindow đóng, ngay cả khi các cửa sổ khác hiện đang mở.

Tuổi thọ của một số ứng dụng có thể không phụ thuộc vào thời điểm đóng cửa sổ chính hoặc cửa sổ cuối cùng, hoặc có thể hoàn toàn không phụ thuộc vào cửa sổ. Đối với những tình huống này, bạn cần đặt thuộc ShutdownModetính OnExplicitShutdown, điều này yêu cầuShutdown lệnh gọi phương thức để dừng ứng dụng. Nếu không, ứng dụng tiếp tục chạy trong nền.

ShutdownMode có thể được định cấu hình khai báo từ XAML hoặc lập trình từ mã.

Thuộc tính này chỉ có sẵn từ luồng đã tạo Applicationđối tượng.


Trong trường hợp của bạn, ứng dụng không đóng vì có thể bạn đang sử dụng cài đặt mặc định OnLastWindowClose:

Nếu bạn đặt ShutdownModethành OnLastWindowClose, WPF sẽ gọi ngầm là Shutdown khi cửa sổ cuối cùng trong ứng dụng đóng, ngay cả khi bất kỳ cửa sổ nào hiện được khởi tạo được đặt làm cửa sổ chính (xem MainWindow).

Vì bạn đang mở một cửa sổ mới và không đóng nó nên việc tắt máy sẽ không được gọi.


1
Điều quan trọng cần lưu ý là chức năng ghi đè là tốt nhất nếu bạn đã khởi tạo bất kỳ Chủ đề nào khác để thực hiện các tác vụ nhất định. Dừng Chủ đề trong chức năng OnClosed trước khi hoàn tất quá trình tắt. Nếu không thì các Chủ đề vẫn tồn tại và ứng dụng không bao giờ thực sự thoát.
frozma2004

35

Tôi rất vui vì bạn đã nhận được câu trả lời của mình nhưng vì lợi ích của những người khác, tôi cũng sẽ trả lời câu hỏi của bạn để thêm một số thông tin.


Bước 1

Đầu tiên, nếu bạn muốn chương trình của mình thoát khi cửa sổ chính đóng lại, bạn cần chỉ định, vì đây không phải là WinForms nơi hành vi này được mặc định.

(Mặc định trong WPF là khi cửa sổ cuối cùng đóng lại)

Trong mã

Đi tới phiên bản ứng dụng của bạn trong điểm nhập của bạn (Trong chương trình WPF của VS 2012, mặc định được lồng vào bên trong App.xaml, vì vậy hãy vào bên trong nó và điều hướng đếnApp.xaml.cs & tạo một phương thức khởi tạo).

Trong constructor xác định rằng bạn Application's ShutdownModenên ShutdownMode. OnLastWindowClose.

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

Trong XAML

Đi tới App.xamlfile VS 2012 tạo ra theo mặc định (hoặc tạo ra nó cho mình) Gốc là một Application, xác định bên trong của bạn Application's ShutdownModenên 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">

Nếu nó hoạt động, bạn đã hoàn thành; bạn có thể ngừng đọc.


Bước 2

Nếu cách trên không hoạt động (tôi đoán bạn đã viết ứng dụng WPF từ đầu), cửa sổ chính có thể không được ứng dụng biết đến là cửa sổ chính. Vì vậy, chỉ định điều đó là tốt.

Trong mã

Đi tới hàm tạo của ứng dụng như bạn đã làm trong Bước 1 và chỉ định điều đó Application. MainWindowGiá trị của là của bạn Window:

MainWindow = mainWindow;

Trong XAML

Đi tới ApplicationXAML như bạn đã làm ở Bước 1 và chỉ định điều đó Application. MainWindowGiá trị của là của bạn Window:

MainWindow = "mainWindow";

Thay thế

Tôi không nghĩ rằng đây là cách tiếp cận tốt nhất, chỉ vì WPF không muốn bạn để làm điều này (vì vậy nó có Application's ShutdownMode), nhưng bạn chỉ có thể sử dụng một sự kiện / ghi đè lên một phương pháp sự kiện (OnEventHappened).

Đi tới tệp mã phía sau của MainWindow và thêm:

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

        App.Current.Shutdown();
    }

3
Câu trả lời của bạn tốt hơn là câu trả lời được đánh dấu.
Seekeer

Tôi thường làm theo cách này: Đặt MainWindowthành thể hiện của cửa sổ chính, đặt ShutdownModethành ShutdownMode.OnMainWindowClose, gọi MainWindow.Show()trong Startupsự kiện gọi lại App. Đây là giải pháp tối thiểu nhất mà tôi đưa ra, hoạt động như mong đợi, ít nhất là trong .NET Core 3 với WPF.
TorbenJ

11

chế độ tắt mặc định trong ứng dụng WPF là OnLastWindowClose, có nghĩa là ứng dụng dừng khi cửa sổ cuối cùng đóng lại.

Khi bạn khởi tạo một đối tượng Window mới, nó sẽ tự động được thêm vào danh sách các cửa sổ trong ứng dụng. Vì vậy, vấn đề là ứng dụng của bạn đang tạo hai cửa sổ khi nó khởi động - MainWindow và Window01 chưa hiển thị - và nếu bạn chỉ đóng MainWindow, thì Window01 sẽ tiếp tục chạy ứng dụng của bạn.

Thông thường, bạn sẽ tạo một đối tượng cửa sổ theo cùng một phương thức sẽ gọi ShowDialog của nó, và bạn sẽ tạo một đối tượng cửa sổ mới mỗi khi hộp thoại được hiển thị.


2

Tôi tình cờ gặp Câu hỏi này khi tìm kiếm thứ gì đó khác và tôi đã ngạc nhiên rằng tôi không thể thấy bất kỳ câu trả lời đề xuất nào đề cập đến Window.Owner.

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

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

Một cuộc gọi đến Window.GetWindow(this)là khá hữu ích trong việc nhìn ra một ứng dụng MVVM khi bạn đang ở xa xuống cây thị giác không biết nơi bạn đã được khởi tạo, nó có thể được gọi bằng cách cung cấp bất kỳ FrameWorkyếu tố (ví dụ UserContol, Button, Page). Rõ ràng nếu bạn có một tham chiếu trực tiếp đến cửa sổ thì hãy sử dụng cái đó hoặc thậm chí Application.Current.MainWindow.

Đây là một mối quan hệ khá mạnh mẽ có một số lợi ích hữu ích mà bạn có thể không nhận ra khi bắt đầu (giả sử bạn chưa mã hóa cụ thể các cửa sổ riêng biệt để tránh các mối quan hệ này).

Nếu chúng tôi gọi cửa sổ chính của bạn MainWindowvà cửa sổ thứ hai là AdditionalWindow...

  1. Giảm thiểu ý MainWindowchí cũng giảm thiểuAdditionalWindow
  2. Khôi phục MainWindowcũng sẽ khôi phụcAdditionalWindow
  3. Đóng MainWindowsẽ đóng AdditionalWindow, nhưng đóng AdditionalWindowsẽ không đóngMainWindow
  4. AdditioanlWindowsẽ không bao giờ bị "mất" bên dưới MainWindow, tức là AddditionalWindowluôn hiển thị ở trên MainWindowtheo thứ tự z nếu bạn đã từng Show()hiển thị nó (khá hữu ích!)

Tuy nhiên, cần lưu ý một điều, nếu bạn có mối quan hệ này, thì Closingsự kiện trên AdditionalWindowkhông được gọi, vì vậy bạn phải lặp lại thủ công qua OwnedWindowsbộ sưu tập. ví dụ: Tạo một cách để gọi từng cửa sổ thông qua Giao diện mới hoặc phương thức lớp cơ sở.

    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

Không có cách nào ở trên phù hợp với tôi, có thể vì dự án của chúng tôi sử dụng Prism. Vì vậy, cuối cùng đã sử dụng điều này trong App.XAML.cs

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

0

Có vẻ như tôi đã gặp phải thứ gì đó khi tạo cửa sổ thứ hai để hoạt động như một hộp thoại. Khi cửa sổ thứ hai được mở và sau đó đóng lại và sau đó cửa sổ chính được đóng lại, ứng dụng vẫn tiếp tục chạy (trong nền). Tôi đã thêm (hoặc xác nhận) những điều sau trong App.xaml của mình:

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

Không có niềm vui.

Vì vậy, cuối cùng tôi đã vào "MainWindow.xaml" của mình và thêm thuộc tính "Đã đóng" vào Cửa sổ, thuộc tính này đã đi đến phương thức "MainWind_Closed" trông giống như sau:

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

Chạy qua trình gỡ lỗi, có vẻ như cửa sổ duy nhất hiển thị là cửa sổ tôi đã tạo dưới dạng hộp thoại - nói cách khác, vòng lặp foreach chỉ tìm thấy một cửa sổ - hộp thoại, không phải cửa sổ chính.

Tôi đã chạy "this.Close ()" trong phương thức đóng hộp thoại và tôi có "dlgwin.Close ()" đến sau "dlgwin.ShowDialog ()" và điều đó không hoạt động. Thậm chí không phải là "dlgwin = null".

Vì vậy, tại sao hộp thoại đó sẽ không đóng lại nếu không có công cụ bổ sung này? Ồ tốt. Những công việc này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.