минимальный автономный WPF/C# для создания экрана-заставки, который отображается в течение x секунд

Мне интересно, почему моя заставка не исчезает через x секунд в приведенном ниже коде? В C# я запускаю поток, который ждет x секунд, а затем пытается отправить close() в окно-заставку, пока оно отображается на экране.

// 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:      [email protected]'/>
    <Label Content='Dates:      2017'/>
</StackPanel>

</Grid>

</Window>
";

    } //end-class

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

Вот пример того, что моя командная строка csc.exe ищет для компиляции вышеуказанного кода С# из системы (...) внутри приложения консольного режима С++:

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"

person Bimo    schedule 21.09.2017    source источник


Ответы (2)


Ваша программа ничего не делает для загрузки очереди сообщений и отправки оконных сообщений окнам. Таким образом, ваша попытка закрыть окно, которая отправляет окну сообщение WM_CLOSE, не имеет никакого эффекта.

Самый простой способ решить эту проблему в вашем примере — использовать win.ShowDialog() вместо win.Show(). Метод ShowDialog() заменяет любой уже запущенный цикл обработки сообщений, заменяя его своим собственным (он делает это, чтобы перехватывать вводимые пользователем сообщения, которые не должны отправляться в другие окна, пока открыто модальное диалоговое окно). Но для этого не требуется, чтобы уже существовал цикл перекачки сообщений, и того, который он запускает, будет достаточно, чтобы получить ваш WM_CLOSE и закрыть окно.

Если вы хотите сделать это более правильно, вы можете добавить в образец объект Application и вызвать Application.Run(), чтобы обеспечить цикл обработки сообщений. Возможно, вы захотите сделать это, если в какой-то момент вы ожидаете, что потребуется отображение нескольких окон или иным образом потребуется немодальный пользовательский интерфейс.

person Peter Duniho    schedule 21.09.2017
comment
Спасибо! После перезаписи и добавления Application.Run(win) все работает. - person Bimo; 21.09.2017
comment
@Bill: судя по твоим вопросам, кажется, что ты так и не принял ни одного предоставленного тебе ответа. Возможно, вы захотите прочитать Что мне делать, когда кто-то ответит на мой вопрос? :) - person Peter Duniho; 22.09.2017

Вот модификации, которые сработали для меня:

// 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
person Bimo    schedule 21.09.2017