Подтвердить что ты не робот

Можно ли "открутить" несколько потоков графического интерфейса? (Не останавливать систему на Application.Run)

Моя цель

Я хотел бы иметь основной поток обработки (non GUI) и иметь возможность откручивать графические интерфейсы в своих собственных потоках фона по мере необходимости, и мой основной поток без GUI будет работать. Иными словами, я хочу, чтобы мой основной non GUI-поток был владельцем GUI-потока, а не наоборот. Я не уверен, что это возможно даже с Windows Forms (?)

Фон

У меня есть компонентная система, в которой контроллер динамически загружает сборки и создает экземпляры и запускает классы, реализующие общий интерфейс IComponent с помощью одного метода DoStuff().

Какие компоненты, которые загружаются, настраиваются с помощью файла конфигурации xml и путем добавления новых сборок, содержащих различные реализации IComponent. Компоненты предоставляют служебные функции для основного приложения. В то время как основная программа делает это, например, контролируя ядерную установку, компоненты могут выполнять служебные задачи (в их собственных потоках), например. очистка базы данных, отправка писем, печать смешных шуток на принтере, что у вас есть. Я хотел бы, чтобы один из этих компонентов мог отображать графический интерфейс пользователя, например. со статусной информацией для указанного компонента отправки электронной почты.

Время жизни всей системы выглядит следующим образом:

  • Запускается приложение.
  • Проверить конфигурационный файл для загрузки компонентов. Загрузите их.
  • Для каждого компонента запустите DoStuff(), чтобы инициализировать его и заставить его жить своей жизнью в своих потоках.
  • Продолжайте делать главное приложение - вечный король работы, навсегда.

Я еще не смог успешно выполнить точку 3, если компонент запускает графический интерфейс в DoStuff(). Он просто останавливается, пока графический интерфейс не будет закрыт. И только после закрытия графического интерфейса программа переходит к пункту 4.

Было бы здорово, если бы этим компонентам было разрешено запускать собственные графические интерфейсы Windows Forms.

Проблема

Когда компонент пытается запустить GUI в DoStuff() (точная строка кода при запуске компонента Application.Run(theForm)), компонент и, следовательно, наша система "зависает" в строке Application.Run() до тех пор, пока графический интерфейс закрыто. Ну, просто запущенный графический интерфейс работает нормально, как и ожидалось.

Пример компонентов. Один не имеет ничего общего с графическим интерфейсом, в то время как второй запускает милые окна с розовыми пушистыми кроликами в них.

public class MyComponent1: IComponent
{
    public string DoStuff(...) { // write something to the database  }
}

public class MyComponent2: IComponent
{
    public void DoStuff()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form());

        // I want the thread to immediately return after the GUI 
        // is fired up, so that my main thread can continue to work.
    }
}

Я пробовал это без везения. Даже когда я пытаюсь запустить GUI в своем потоке, выполнение останавливается, пока GUI не будет закрыт.

public void DoStuff()
{
    new Thread(ThreadedInitialize).Start()
}

private void ThreadedInitialize()
{
    Application.EnableVisualStyles();
    Application.SetCompatibleTextRenderingDefault(false);
    Application.Run(new Form());
}

Можно ли отключить графический интерфейс и вернуться после Application.Run()?

4b9b3361

Ответ 1

Метод Application.Run отображает одну (или более) формы и инициирует стандартный цикл сообщений, который продолжается до тех пор, пока все формы не будут закрыты. Вы не можете принудительно возвратить этот метод, за исключением закрытия всех ваших форм или принудительного выключения приложения.

Однако вы можете передать ApplicationContext (instad для нового метода Form()) в Application.Run и ApplicationContext, который можно использовать для запуска сразу нескольких форм. Ваше приложение будет прекращено только после закрытия всех этих приложений. См. Здесь: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

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

Ответ 2

Я уверен, что это возможно, если вы достаточно сильно взломаете его, но я бы предложил, что это не очень хорошая идея.

"Windows" (который вы видите на экране) тесно связан с процессами. То есть каждый процесс, который отображает любой графический интерфейс, как ожидается, будет иметь Loop сообщения, который обрабатывает все сообщения, связанные с созданием и управлением окнами (такие вещи, как "нажмите кнопку", "закрыть приложение", "перерисовать экран" 'и т.д.

Из-за этого более или менее предполагается, что если у вас есть какой-либо цикл сообщений, он должен быть доступен для всего жизненного цикла вашего процесса. Например, окна могут отправлять вам сообщение "quit", и вам нужно иметь доступ к контуру сообщения, даже если на экране ничего нет.

Лучше всего сделать это так:

Сделайте фальшивую форму, которая никогда не отображается, которая является вашим "основным приложением", Запускать Вызовите Application.Run и перейдите в эту фальшивую форму. Делайте свою работу в другом потоке и запускайте события в основном потоке, когда вам нужно делать вещи Gui.

Ответ 3

Я не уверен, правильно ли это, но я помню, как запускал оконные формы из консольного приложения, просто создавая форму и вызывая на ней newForm.Show(), если ваши компоненты используют это вместо Application.Run() то новая форма не должна блокироваться.

Конечно, компонент будет отвечать за поддержание ссылки на формы, которые он создает.