2

I'm wondering, why doesn't my splash screen disappear after x seconds in the code below? In C#, I start a thread, that waits x seconds, then tries to dispatch a close() to the splash window while its being shown on the screen.

// FILE: splashy.cs
using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Windows;
using System.Windows.Markup;
using System.Threading;

namespace Splashy
{
    class MySplash
    {
        Window win;

        public void Show()
        {
            var mem     = new MemoryStream(
                            ASCIIEncoding.UTF8.GetBytes(xmlstr));

            win         = (Window)XamlReader.Load(mem);
            (new Thread(CloseIt)).Start();
            win.Show();
        }

        public void CloseIt() {
            Thread.Sleep(4*1000);
            //MessageBox.Show("CLOSE");
            win.Dispatcher.Invoke(() => win.Close());
        }

        static string xmlstr = @"
<Window
  xmlns='http://schemas.microsoft.com/winfx/2006/xaml/presentation'
  xmlns:x='http://schemas.microsoft.com/winfx/2006/xaml'
  Name='WindowSplash'
  Title='My Splash Window...'
  WindowStyle='None'
  WindowStartupLocation='CenterScreen'
  Background='White'
  ShowInTaskbar ='true'
  Width='350' Height='130'
  ResizeMode = 'NoResize' >

<Window.Resources>
    <Style TargetType='{x:Type Label}'>
            <Setter Property='FontFamily' Value='Consolas'/>
            <Setter Property='Background' Value='Blue'/>
            <Setter Property='Foreground' Value='AntiqueWhite'/>
    </Style>
</Window.Resources>

<Grid>

<Grid.RowDefinitions>
    <RowDefinition Height='Auto'/>
    <RowDefinition Height='*'/>
    <RowDefinition Height='Auto'/>
</Grid.RowDefinitions>

<Grid.ColumnDefinitions>
    <ColumnDefinition Width='Auto'/>
    <ColumnDefinition Width='*'/>
</Grid.ColumnDefinitions>

<Label
    Grid.ColumnSpan='2'
    Grid.Row='0'
    Content='MyApplication 1.0'
    FontWeight='Bold'
    FontFamily='Consolas'
    Background='AntiqueWhite'
    Foreground='Black'/>

<Label
    Grid.ColumnSpan='2'
    Grid.Row='2'
    Content=''
    FontWeight='Bold'
    FontFamily='Consolas'
    Background='AntiqueWhite'
    Foreground='Black'/>


<Label
    Grid.Column='0'
    Grid.Row='1'
    FontFamily='Webdings' Content='&#xc2;' FontSize='80' />

<StackPanel
    Grid.Row='1'
    Grid.Column='1'
    Background='Blue'
    >
    <Label Content='Programmer: John Smith'/>
    <Label Content='Email:      john.smith@gmail.com'/>
    <Label Content='Dates:      2017'/>
</StackPanel>

</Grid>

</Window>
";

    } //end-class

    class MyApp 
    {
        [STAThread]
        static void Main(string[] args)
        {
            (new MySplash()).Show();
        }
    } //end-class
} //end-namespace

Here's an Example of what my csc.exe command line looks for compiling above c# code from system(...) inside of console mode c++ application:

C:\WINDOWS\Microsoft.Net\Framework64\v4.0.30319\csc.exe 
/out:splashy.exe 
/nologo  
/target:winexe 
splashy.cs 
/reference:"C:\WINDOWS\Microsoft.Net\Framework64\v4.0.30319\WPF\presentationframework.dll" 
/reference:"C:\WINDOWS\Microsoft.Net\Framework64\v4.0.30319\WPF\windowsbase.dll" 
/reference:"C:\WINDOWS\Microsoft.Net\Framework64\v4.0.30319\WPF\presentationcore.dll" 
/reference:"C:\WINDOWS\Microsoft.Net\Framework64\v4.0.30319\System.Xaml.dll"
Bimo
  • 5,987
  • 2
  • 39
  • 61

2 Answers2

1

Your program does nothing to pump the message queue and dispatch window messages to windows. So your attempt to close the window, which sends a WM_CLOSE message to the window, has no effect.

The easiest way to solve this in your example would be to use win.ShowDialog() instead of win.Show(). The ShowDialog() method supersedes whatever message-pump loop is already running, replacing it with its own (it does this so it can intercept user-input messages that shouldn't be dispatched to other windows while the modal dialog is up). But it doesn't require that there already be a message-pump loop, and the one it runs will suffice to receive your WM_CLOSE and close the window.

If you want to do it more properly, you can add an Application object to your sample and call Application.Run() to provide the message-pump loop. You might want to do this if you at some point expect to require showing multiple windows or otherwise require a non-modal UI.

Peter Duniho
  • 68,759
  • 7
  • 102
  • 136
0

These are the modifications that worked for me:

// FILE: splashy.cs
using System;
using System.IO;
using System.Xml;
using System.Text;
using System.Windows;
using System.Windows.Markup;
using System.Threading;

namespace Splashy
{
    class MySplash
    {
        Window win;

        public Window CreateWindow()
        {
            var mem     = new MemoryStream(
                              ASCIIEncoding.UTF8.GetBytes(xmlstr));
            win         = (Window)XamlReader.Load(mem);
            (new Thread(CloseIt)).Start();
            return win;
        }

        public void CloseIt() {
            Thread.Sleep(2000);
            Application.Current.Dispatcher.Invoke(() => {
                win.Close();
            });
        }

        [STAThread]
        static void Main(string[] args)
        {
            Application app    = new Application();
            MySplash    splash = new MySplash();
            Window      win    = splash.CreateWindow();
            app.Run(win);
        }

        static string xmlstr = @"
            <Windows ...> 
            <!-- ...  Omitted to save space ... --> 
            <Window/>
        ";

    } //end-class
} //end-namespace
Bimo
  • 5,987
  • 2
  • 39
  • 61