É possível “desmembrar” vários threads da GUI?(Não interrompendo o sistema em Application.Run)

StackOverflow https://stackoverflow.com/questions/2872

  •  08-06-2019
  •  | 
  •  

Pergunta

Meu gol

Eu gostaria de ter um thread de processamento principal (não GUI) e ser capaz de desmembrar GUIs em seus próprios threads de segundo plano, conforme necessário, e fazer com que meu thread principal não GUI continue funcionando.Dito de outra forma, quero que meu thread principal não GUI seja o proprietário do thread GUI e não vice-versa.Não tenho certeza se isso é possível com o Windows Forms (?)

Fundo

Eu tenho um sistema baseado em componentes no qual um controlador carrega dinamicamente assemblies e instancia e executa classes implementando um comum IComponent interface com um único método DoStuff().

Quais componentes carregados são configurados por meio de um arquivo de configuração xml e pela adição de novos assemblies contendo diferentes implementações de IComponent.Os componentes fornecem funções utilitárias para o aplicativo principal.Enquanto o programa principal está fazendo isso, por ex.controlando uma usina nuclear, os componentes podem estar executando tarefas utilitárias (em seus próprios threads), por exemplo.limpando o banco de dados, enviando e-mails, imprimindo piadas engraçadas na impressora, o que quer que seja.O que eu gostaria é que um desses componentes fosse capaz de exibir uma GUI, por exemplo.com informações de status para o referido componente de envio de e-mail.

A vida útil do sistema completo é assim

  1. O aplicativo é iniciado.
  2. Verifique o arquivo de configuração para carregar os componentes.Carregue-os.
  3. Para cada componente, execute DoStuff() para inicializá-lo e fazê-lo viver sua própria vida em seus próprios threads.
  4. Continue a fazer o trabalho principal do aplicativo, para sempre.

Ainda não consegui executar com êxito o ponto 3 se o componente iniciar uma GUI em DoStuff().Ele simplesmente para até que a GUI seja fechada.E só depois que a GUI for fechada o programa avança para o ponto 4.

Seria ótimo se esses componentes pudessem iniciar suas próprias GUIs do Windows Forms.

Problema

Quando um componente tenta iniciar uma GUI em DoStuff() (a linha exata do código é quando o componente é executado Application.Run(theForm)), o componente e, portanto, nosso sistema "trava" no Application.Run() linha até que a GUI seja fechada.Bem, a GUI recém-iniciada funciona bem, como esperado.

Exemplo de componentes.Um não tem nada a ver com GUI, enquanto o segundo abre janelas fofas com coelhinhos rosa fofos.

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.
    }
}

Eu tentei isso sem sorte.Mesmo quando tento iniciar a GUI em seu próprio thread, a execução é interrompida até que a GUI seja fechada.

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

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

É possível desmembrar uma GUI e retornar depois Application.Run()?

Foi útil?

Solução

Aplicativo.Executar O método exibe um (ou mais) formulários e inicia o loop de mensagem padrão que é executado até que todos os formulários sejam fechados.Você não pode forçar o retorno desse método, exceto fechando todos os seus formulários ou forçando o encerramento do aplicativo.

Você pode, no entanto, passar um ApplicationContext (instad de um novo Form()) para o método Application.Run e ApplicationContext pode ser usado para iniciar vários formulários ao mesmo tempo.Sua inscrição só terminará quando todas elas forem encerradas.Veja aqui: http://msdn.microsoft.com/en-us/library/system.windows.forms.application.run.aspx

Além disso, quaisquer formulários que você mostrar de forma não modal continuarão a ser executados junto com o formulário principal, o que permitirá que você tenha mais de uma janela que não bloqueie umas às outras.Eu acredito que isso é realmente o que você está tentando realizar.

Outras dicas

Tenho certeza de que isso é possível se você tentar com força suficiente, mas sugiro que não é uma boa ideia.

As 'Windows' (que você vê na tela) estão altamente acopladas aos processos.Ou seja, espera-se que cada processo que exibe qualquer GUI tenha um Message Loop, que processa todas as mensagens envolvidas na criação e gerenciamento de janelas (coisas como 'cliquei no botão', 'fechei o aplicativo', 'redesenhei a tela ' e assim por diante.

Por causa disso, presume-se mais ou menos que, se você tiver algum loop de mensagem, ele deverá estar disponível durante a vida útil do seu processo.Por exemplo, o Windows pode enviar uma mensagem de 'sair' e você precisa ter um loop de mensagens disponível para lidar com isso, mesmo que não haja nada na tela.

Sua melhor aposta é fazer assim:

Faça uma forma falsa que nunca é mostrada, qual é o seu aplicativo 'principal' Start -up Call Application.Run e passe nessa forma falsa.Faça seu trabalho em outro thread e dispare eventos no thread principal quando precisar fazer coisas do Gui.

Não tenho certeza se isso está certo, no entanto, lembro-me de executar formulários de janela a partir de um aplicativo de console apenas atualizando o formulário e chamando newForm.Show() nele, se seus componentes usarem isso em vez de Application.Run() então o novo formulário não deve bloquear.

É claro que o componente será responsável por manter uma referência aos formulários que ele cria

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top