Search code examples
c#wpfsplash-screen

How to close a window after opening a second window in a thread in wpf?


I created a waiting window that stays open to view the software loading. When the software finishes the calculations, it opens the main window... and I wanted to close the waiting window...

So I found this code

Thread thread = new Thread(() =>
{

 PopupAtt proc = new();
 proc.Show();

 proc.Closed += (sender2, e2) =>
  proc.Dispatcher.InvokeShutdown();
 proc.Owner = Window.GetWindow(this);
 System.Windows.Threading.Dispatcher.Run();
 
 });

 thread.SetApartmentState(ApartmentState.STA);
 thread.Start();
 thread.IsBackground = true;

to create threads and it works well, it opens the waiting window with the loading percentage and then the main window opens, but it does not close the waiting window... I did not find a way to close the waiting window thread, but it closes only when the whole program is closed. How can I close only the waiting window?


Solution

  • Analysis

    In WPF like in many other UI frameworks from multiple programming languages assign the thread that is initiating the application as the UI thread.

    // SUPERFLUOUS THREAD INVOCATION
    Thread thread = new Thread(() =>
    {
    
     PopupAtt proc = new();
     proc.Show();
    
     proc.Closed += (sender2, e2) =>
      proc.Dispatcher.InvokeShutdown();
     proc.Owner = Window.GetWindow(this);
    
     // SUPERFLOUS MIGRATION OF THE CURRENT THREAD PROCESS TO THE UI THREAD
     System.Windows.Threading.Dispatcher.Run();
     
    });
    
    thread.SetApartmentState(ApartmentState.STA);
    thread.Start();
    thread.IsBackground = true;
    

    As the comments made by me point out, the creation of the thread object as well as migrating its operation to the UI thread are superfluous, meaning that the whole operation is unnecessary.

    Solution

    The core mechanism of an WPF application is that as long as an window is opened, the application will keep running. The main mechanisms for opening an window is to instantiate an object from the class that implements the window object and either to call Show() or ShowDialog(). The difference between these 2 is that Show() will open a window that is independent of the parent window, whereas ShowDialog() will open a window that is dependent on the parent window and that is also preventing the user to interact with the parent window until the current child window is closed. The desired mechanism for your problem will be to initiate the window that is processing the calculation at the startup of the application and when the calculation is finished, to open the main window and close the window that performed the calculation.

    Firstly, the window that is performing the calculation must be set to be initiated at the startup of the application. This can be done by setting the StartupUri parameter within the App.xaml file as the name of the window that is doing the calculation, which in this example is Processing.

    <!--
        App.xaml
    -->
        
    <Application x:Class="StackOverflow.App"
                 xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
                 xmlns:local="clr-namespace:StackOverflow"
                 StartupUri="Processing.xaml">
        <Application.Resources>
             
        </Application.Resources>
    </Application>
    

    Secondly, after the window performs the calculation, an object from the main window object must be instantiated, the window must be created by using the Show() method, and afterwards the current window must be closed. It is preferable to initiate the calculation when the window loaded. To do this, simply use the Loaded property of the window object within the XAML section and give the method name for this Loaded event

    <!--
        Processing.xaml
    -->
        
    <Window x:Class="StackOverflow.Processing"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:StackOverflow"
            mc:Ignorable="d"
            Title="Processing" Height="450" Width="800" Loaded="Calculate_the_values" >
        <Grid>
            <TextBlock x:Name="Calculate_Label" HorizontalAlignment="Center" VerticalAlignment="Center" Text="Calculate the values" FontSize="40"/>
        </Grid>
    </Window>
    
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Shapes;
    
    namespace StackOverflow
    {
        // Processing.cs
    
        /// <summary>
        /// Interaction logic for Processing.xaml
        /// </summary>
        public partial class Processing : Window
        {
            private int percent = 0;
            public Processing()
            {
                InitializeComponent();
            }
    
            // LOADED EVENT
            private void Calculate_the_values(object sender, RoutedEventArgs e)
            {
    
                System.Timers.Timer timer = new System.Timers.Timer();
                timer.Elapsed += Timer_Elapsed;
                timer.Interval = 200;
                timer.Start();
    
            }
    
            private async void Timer_Elapsed(object? sender, System.Timers.ElapsedEventArgs e)
            {
                percent += 10;
                await Application.Current.Dispatcher.InvokeAsync(() =>
                {
    
                    Calculate_Label.Text = $"Progress: {percent}%";
                    if (percent == 100)
                    {
                        new MainWindow().Show();
                        this.Close();
                        ((System.Timers.Timer?)sender)?.Dispose();
                    }
                });
            }
        }
    }
    
    
    <!--
        MainWindow.xaml
    -->
    
    <Window x:Class="StackOverflow.MainWindow"
            xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
            xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
            xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
            xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
            xmlns:local="clr-namespace:StackOverflow"
            mc:Ignorable="d"
            Title="MainWindow" Height="450" Width="800" Loaded="Window_Loaded" Background="Green">
        <Grid>
            <TextBlock HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="50" FontWeight="Bold" Foreground="White" Text="Main Window"/>
        </Grid>
    </Window>
    
    
    using System.Text;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Data;
    using System.Windows.Documents;
    using System.Windows.Input;
    using System.Windows.Media;
    using System.Windows.Media.Imaging;
    using System.Windows.Navigation;
    using System.Windows.Shapes;
    
    namespace StackOverflow
    {
        // MainWindow.cs
    
        /// <summary>
        /// Interaction logic for MainWindow.xaml
        /// </summary>
        public partial class MainWindow : Window
        {
            Processing processing = new Processing();
    
            public MainWindow()
            {
                InitializeComponent();
            }
    
            public MainWindow(Processing _processing)
            {
                InitializeComponent();
                processing = _processing;
            }
    
            private void Window_Loaded(object sender, RoutedEventArgs e)
            {
                processing.Close();
            }
        }
    }
    

    Application output example