Проблемы с заставкой
DoEvents очень нежелательна и не обязательно выполняет то, что вы думаете.DoEvents указывает CLR присутствовать в цикле сообщений Windows (для заставки), но не обязательно предоставляет время обработки другим потокам.Thread.Sleep()
предоставит другим потокам возможность обрабатывать, но не обязательно позволит циклу сообщений Windows для вашего заставки продолжать отправку сообщений.Так что вам действительно нужны оба, если вы должны использовать цикл, но через минуту я порекомендую вообще отказаться от этого цикла.В дополнение к этой проблеме цикла, я не вижу какого-либо явного способа очистки потока-заставки.Вам нужно что-то вроде Thread.Join()
или Thread.Abort()
.
Вместо использования цикла Application.DoEvents()
я хотел бы использовать ManualResetEvent для синхронизации форм-заставок, запускаемых с вызывающим потоком.Таким образом, метод ShowSplash () не возвращается, пока не отобразится заставка.В любое время после этого мы, очевидно, можем закрыть его, так как знаем, что его показ завершен.
Вот цепочка с несколькими хорошими примерами: Многопоточные заставки .NET в C #
Вот как я изменил мой любимый пример, опубликованный @AdamNosfinger, для включения ManualResetEvent для синхронизации метода ShowSplash с потоком заставки:
public partial class FormSplash : Form
{
private static Thread _splashThread;
private static FormSplash _splashForm;
// This is used to make sure you can't call SplashScreenClose before the SplashScreenOpen has finished showing the splash initially.
static ManualResetEvent SplashScreenLoaded;
public FormSplash()
{
InitializeComponent();
// Signal out ManualResetEvent so we know the Splash form is good to go.
SplashScreenLoaded.Set();
}
/// <summary>
/// Show the Splash Screen (Loading...)
/// </summary>
public static void ShowSplash()
{
if (_splashThread == null)
{
// Setup our manual reset event to syncronize the splash screen thread and our main application thread.
SplashScreenLoaded = new ManualResetEvent(false);
// show the form in a new thread
_splashThread = new Thread(new ThreadStart(DoShowSplash));
_splashThread.IsBackground = true;
_splashThread.Start();
// Wait for the splash screen thread to let us know its ok for the app to keep going.
// This next line will not return until the SplashScreen is loaded.
SplashScreenLoaded.WaitOne();
SplashScreenLoaded.Close();
SplashScreenLoaded = null;
}
}
// called by the thread
private static void DoShowSplash()
{
if (_splashForm == null)
_splashForm = new FormSplash();
// create a new message pump on this thread (started from ShowSplash)
Application.Run(_splashForm);
}
/// <summary>
/// Close the splash (Loading...) screen
/// </summary>
public static void CloseSplash()
{
// need to call on the thread that launched this splash
if (_splashForm.InvokeRequired)
_splashForm.Invoke(new MethodInvoker(CloseSplash));
else
Application.ExitThread();
}
}
Основные проблемы с формой
Похоже, что вы запускаете свою основную форму из окна входа в систему, используя ShowDialog, а затем закрываете форму входа.Я правильно понял?Это не хорошо, если так.ShowDialog предназначен для дочерних окон вашего приложения и хочет иметь окно владельца, если вы не указываете форму владельца в аргументах метода, текущее активное окно считается владельцем.См. MSDN
Итак, ваша основная форма предполагает, что форма входа в систему является ее родителем, но вы закрываете форму входа вскоре после отображения основной формы.Поэтому я не уверен, в каком состоянии находится приложение на тот момент.Вместо этого следует рассмотреть возможность использования стандартного метода Form.Show()
и простой настройки свойств формы, чтобы они отображались в виде диалога, если это желаемый результат (например, BorderStyle, MaximizeBox, MinimizeBox, ControlBox, TopMost).
ВАЖНОЕ РЕДАКТИРОВАНИЕ: Хорошо, я человек, я все испортил и забыл, что ShowDialog был методом блокировки.Хотя это устраняет проблему с ручкой владельца, я все же рекомендую не использовать ShowDialog для основной формы приложения, если только вы не можете предоставить существенное обоснование для него, которое не связано с внешним видом или потоками (поскольку это должно быть исправлено другими методами).Совет все еще здравый, несмотря на ошибку с моей стороны.
Возможные проблемы с окраской
Вы не указали, какие элементы управления вы использовали или выполняли какие-либо пользовательские рисунки в своем приложении.Но вы должны иметь в виду, что некоторые дескрипторы окон будут принудительно закрываться при блокировке компьютера.Например, если у вас есть какие-то пользовательские элементы управления для рисования, и вы кэшируете шрифты, кисти или другие ресурсы GDI, вам нужно иметь в своем коде несколько блоков try { ... } catch { ... }
, которые утилизируют, а затем перестраивают кэшированные ресурсы GDI при возникновении исключения во время рисования.Я сталкивался с этим раньше, когда я рисовал окно списка и кэшировал некоторые объекты GDI.Если у вас есть какой-либо пользовательский код рисования где-либо в вашем приложении, в том числе на заставке, пожалуйста, проверьте, что все объекты GDI удачно расположены / очищены.