Как заставить программу работать в фоне после закрытия части с интерфейсом?

Сегодня написал свой первый более-менее серьезный проект на C# - тайм менеджер. У меня есть система заметок, которые создаёт пользователь и функция, которая проверяет дату и время с заданными пользователем, а потом вызывает всплывающее окошко с информацией о надвигающемся событии. Подскажите, как можно реализовать работу приложения в фоне? К примеру: человек закрывает всю программу имеющую GUI на крестик, но должен быть процесс работающий в фоне, который будет отсчитывать время и выводить окошко события, а так же не будет виден на приборной панели(завершить его можно только через диспетчер задач или отключением ПК). Как я могу создать нечто подобное? Вопрос, наверное, сложный в реализации, потому буду рад даже малейшей теории и идеям без единой строчки кода


Ответы (3 шт):

Автор решения: Pavlo Khyzhniak

Создай поток с нужной задачей, который будет продолжать работать после закрытия 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;
    }
→ Ссылка
Автор решения: Psyxoz0x13

Есть библиотека, вот ссылка 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"/>
→ Ссылка
Автор решения: Pavel Mayorov

Это делается куда проще чем кажется. Разгадка - в файле Program.cs. Обратите внимание на вот эту строчку:

Application.Run(new Form1());

Метод Application.Run, если по-простому, рисует вам пользовательский интерфейс до тех пор, пока переданная ему форма (называемая "главной" формой) не будет закрыта, после чего завершается. А поскольку он обычно является последней строчкой в методе Main - то после закрытия главной формы программа завершается.

Как это обойти? Очень просто, и есть аж два способа:

  1. не передавать методу форму:

    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();
    
  2. не делать метод последней строчкой:

    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());
    }
    
→ Ссылка