Как заставить программу работать в фоне после закрытия части с интерфейсом?
Сегодня написал свой первый более-менее серьезный проект на C# - тайм менеджер. У меня есть система заметок, которые создаёт пользователь и функция, которая проверяет дату и время с заданными пользователем, а потом вызывает всплывающее окошко с информацией о надвигающемся событии. Подскажите, как можно реализовать работу приложения в фоне? К примеру: человек закрывает всю программу имеющую GUI на крестик, но должен быть процесс работающий в фоне, который будет отсчитывать время и выводить окошко события, а так же не будет виден на приборной панели(завершить его можно только через диспетчер задач или отключением ПК). Как я могу создать нечто подобное? Вопрос, наверное, сложный в реализации, потому буду рад даже малейшей теории и идеям без единой строчки кода
Ответы (3 шт):
Создай поток с нужной задачей, который будет продолжать работать после закрытия UI
delegate void threadMethod(object obj);
private Thread CreateThread(threadMethod method)
{
Thread thread = null;
try
{
if (thread == null)
{
// Создать параметрический поток (параметр - потоковая функция)
ParameterizedThreadStart parameterized = new ParameterizedThreadStart(method);
// Сосздать поток
thread = new Thread(parameterized);
// Закрыть ли поток при закрытии окна
thread.IsBackground = false;
// // Старт потока
thread.Start();
}
}
catch { }
return thread;
}
А запараметрировать можно вот так например:
void threadCurrentFunction(object obj)
{
while(true)
{
//есть что делать
}
//по завершению потока, когда то его нужно закрыть
threadCurrent?.Abort();
threadCurrent = null;
}
Есть библиотека, вот ссылка https://github.com/Psyxoz13/Native.
все довольно просто, подключите эту библиотеку:
using Native.Window;
и вставьте вот этот код:
var window = Window.GetFromHandle(Handle);
window.State = WindowState.Hide;
и приложение будет работать в фоновом режиме. Библиотека работает с winapi функциями на которых и работают winforms. если что-то не получается значит нужно запустить от имени администратора. В файле манифеста, если его нет - создать, заменить
<requestedExecutionLevel level="asInvoker" uiAccess="false"/>
на
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
Это делается куда проще чем кажется. Разгадка - в файле Program.cs. Обратите внимание на вот эту строчку:
Application.Run(new Form1());
Метод Application.Run, если по-простому, рисует вам пользовательский интерфейс до тех пор, пока переданная ему форма (называемая "главной" формой) не будет закрыта, после чего завершается. А поскольку он обычно является последней строчкой в методе Main - то после закрытия главной формы программа завершается.
Как это обойти? Очень просто, и есть аж два способа:
не передавать методу форму:
new Form1().Show(); Application.Run();Метод
Application.Run, вызванный без параметров, не вернёт управления пока не будет вызван методApplication.ExitThread. Разумеется, он также и не отобразит сам никакой формы - поэтому форму нужно показать заранее отдельной строчкой.Разумеется, отображать форму именно заранее не обязательно - вы можете сделать это в любой удобный момент, в том числе по таймеру:
var timer = new Timer { Interval = 3600000 }; timer.Tick += (o, e) => { new Form1().Show(); }; timer.Start(); Application.Run();не делать метод последней строчкой:
Application.Run(new Form1()); Application.Run(new Form2()); Application.Run(new Form3());Как я уже писал выше, программа завершает свою работу не из-за закрытия главного окна, а из-за того что завершается метод Main. Если после вызова
Application.Runметод не завершится - то и программа не закончит работу. МетодApplication.Runможно вызывать столько раз, сколько потребуется. К примеру, код выше последовательно покажет пользователю три разные формы.Пример отображения окна по таймеру:
while (true) { Thread.Sleep(TimeSpan.FromHours(1)); Application.Run(new Form1()); }