В одном из проектов, которые я поддерживаю, нашел очень интересную реализацию SplashScreen'а.
SplashScreen - это окно, которое отображается пользователю, когда приложение долгое время выполняет какую-то работу и не может отвечать на действия пользователя.
Обычно для реализации такого окна создается второй Thread, в котором отображается SplashScreen, а в первом Thread'e выполняется вся работа. Это позволяет избавиться от эффекта "зависшего" приложения.
В данном случае реализация SplashScreen'а разделена на 2 части:
- WaitManager.cs
- WaitForm.cs
Код WaitManager'а выглядит следующим образом:
public class WaitManager : IDisposable
{
Thread myThread;
WaitForm frm;
bool shown = false;
public bool Finished { get; private set; }WaitForm - это форма, которая отобразится пользователю. На форму добавлен таймер (о нем позже) и ссылка на WaitManager, которая передается в конструктор объекта формы:
public WaitManager()
{
Finished = false;
myThread = new Thread(DoWork);
myThread.Start();
}
void DoWork()
{
frm= new WaitForm(this, progressFunc);
frm.Shown += new EventHandler(frm_Shown);
frm.ShowDialog();
}
void frm_Shown(object sender, EventArgs e)
{
shown = true;
}
public void Dispose()
{
Finished = true;
while (!shown || frm.Visible)
Thread.Sleep(1);
myThread.Abort();
}
}
public partial class WaitForm : FormСамое интересное в этой реализации - то, как легко происходит вызов SplashScreen'а:
{
WaitManager manager;
private WaitForm(WaitManager manag)
{
InitializeComponent();
manager = manag;
timer = DateTime.Now;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (manager.Finished)
Close();
}
}
using (new WaitManager ())Всё, что нужно сделать для отображения SplashScreen'а - добавить одну строку кода + фигурные кавычки.
{
DoSomeStuff();
}
Как это работает:
- При создании нового экземпляра WaitManager'а создается новый поток, в котором создается и отображается новый экземпляр WaitForm'ы
- В когда метод DoSomeStuff() в основном потоке заканчивает свое выполнение, при выходе из области using вызовется метод WaitManager'а Dispose (для этого и нужна реализация IDisposable).
- WaitManager сигнализирует WaitForm'e, что он готов завершить ее поток (Finished = true)
- Таймер в WaitForm'e периодически проверяет, не сигнализирует ли WaitManager о готовности завершить поток (см. 3)
- Если Finished==true, то вызывается закрытие формы
- После этого WaitManager завершает поток, в котором была открыта форма, и передает управление вызывающему коду
В целом, реализация довольно логичная и простая, но в интернете подобной реализации я не встречал.
PS. Автор кода - не я. К сожалению, никаких контактов автора этого решения у меня нет.
Комментариев нет:
Отправить комментарий