Почему этот код заставляет мою форму исчезнуть? - PullRequest
0 голосов
/ 13 декабря 2010

Поскольку я добавил заставку, моя основная форма иногда (примерно 1 раз в 20 раз) исчезает, как будто она свернута (она будет невидимой, но все равно будет оставаться на панели задач, и если я нажму на нее, она появится снова).Вот мой код:

static class Program
{
    private static SplashScreen splashScreen = null;
    private static ManualResetEvent splashScreenWaiter = null;
    /// <summary>
    /// The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        ShowSplashAsync();
        BuilderForm2 builderForm2 = new BuilderForm2();
        builderForm2.Shown += new EventHandler(builderForm2_Shown);
        Application.Run(builderForm2);
    }

    private static void HideSplash()
    {
        if (splashScreenWaiter != null)
        {
            splashScreenWaiter.WaitOne();
            splashScreen.Invoke(new Action(splashScreen.Close));
            splashScreenWaiter = null;
            splashScreen = null;
        }
    }

    private static void builderForm2_Shown(object sender, EventArgs e)
    {
        HideSplash();
    }

    private static void ShowSplashAsync()
    {
        splashScreenWaiter = new ManualResetEvent(false);
        Thread splashThread = new Thread(ShowSplash);
        splashThread.IsBackground = true;
        splashThread.SetApartmentState(ApartmentState.STA);
        splashThread.Start(splashScreenWaiter);
    }

    private static void ShowSplash(object resetEvent)
    {
        splashScreen = new SplashScreen((ManualResetEvent)resetEvent);
        Application.Run(splashScreen);
    }
}

А это код SplashScreen:

public partial class SplashScreen : Form
{
    private ManualResetEvent ResetEvent;
    bool handleCreated = false;
    bool formShown = false;

    public SplashScreen(ManualResetEvent resetEvent)
    {
        ResetEvent = resetEvent;
        HandleCreated += new EventHandler(SplashScreen_HandleCreated);
        InitializeComponent();
    }

    private void SetResetEventIfReady()
    {
        if(handleCreated && formShown) ResetEvent.Set();
    }

    private void SplashScreen_Shown(object sender, EventArgs e)
    {
       formShown = true;
       SetResetEventIfReady();
    }

    void SplashScreen_HandleCreated(object sender, EventArgs e)
    {
        handleCreated = true;
        SetResetEventIfReady();
    }
}

1 Ответ

4 голосов
/ 13 декабря 2010

Ничего не выпрыгивает. Однако в вашем коде есть очень серьезное состояние гонки. Это связано с классом SystemEvents. Этот класс предоставляет важные уведомления для элементов управления, чтобы они могли отвечать пользователю, меняющему тему Windows. Этот класс нуждается в скрытом окне уведомлений для получения сообщений об изменениях, внесенных пользователем.

Это идет очень неправильно, если первое окно вашей программы создано в рабочем потоке вместо потока пользовательского интерфейса. Это заставляет класс SystemEvents создавать это окно уведомлений не в том потоке (а не в вашем рабочем потоке). И события, которые он вызывает, будут вызваны из этой ветки. Получение события в неправильном потоке создает хаос, элементы управления не являются потоко-безопасными. Наиболее типичным результатом является то, что при блокировке рабочей станции у вас возникнут странные проблемы с рисованием или тупики формы. Я могу себе представить, что то, что вы видите неправильно, может быть объяснено и этим.

.NET Framework уже имеет отличную и проверенную временем поддержку для заставок. Я рекомендую вам использовать его вместо того, чтобы крутить свой собственный. Проверьте этот ответ для кода.

Если вы хотите сохранить свои собственные, тогда вы можете обойти проблему гонки, вставив эту строку кода в свой метод Main перед вызовом ShowSplashAsync:

  Microsoft.Win32.SystemEvents.UserPreferenceChanged += delegate { };
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...