Pergunta

Estou mostrando uma tela de respingo em um tópico de segundo plano enquanto meu programa carrega. Depois de carregar, estou abortando o fio, pois o único objetivo era mostrar uma forma de respingo de carregamento agora.

Meu problema é que, ao abortar um fio, joga um ThreadAbortException que o usuário pode simplesmente clicar em continuar.

Como faço para lidar com isso? Eu estava tentando suprimir assim ->

            try
        {
            Program.splashThread.Abort();
        }
        catch(Exception ex)
        {

        }

Mas tenho a sensação de que vai me fazer gritar aqui e não funciona de forma alguma.

Obrigado!

Foi útil?

Solução

Você não precisa cancelar o tópico. Vou exemplificar com o código.

No formulário de tela Splash:

public void CloseSplash()
{
    Invoke((MethodInvoker)delegate
    {
        this.Close();
    });
}

No arquivo program.cs:

private static Splash _splash = null;
public static void CloseSplash()
{
    if (_splash!= null)
    {
        _splash.CloseSplash();
    }
}

Agora, quando seu método principal começar, mostre o respingo em um tópico:

Thread t = new Thread(new ThreadStart(delegate
{
    _splash = new Splash();
    _splash.ShowDialog();
}));

t.Start();

... e quando você quiser fechar, basta fechar:

Program.CloseSplash();

Então você não precisa se preocupar em abortar o fio; Vai sair graciosamente.

Outras dicas

Consulte o link a seguir obtido fazendo uma pesquisa no Google (primeiro resultado retornado):

http://msdn.microsoft.com/en-us/library/5b50fdsz.aspx

Preste atenção especial a esta parte:

Quando esse método é chamado em um fio, o sistema lança um ThreadAborTexception no tópico para abortá -lo. ThreadAborTexception é uma exceção especial que pode ser capturada pelo código do aplicativo, mas é renovado no final do bloco de captura, a menos que Resetabort é chamado. Resetabort cancela o pedido de abortar e impede o ThreadAborTexception de encerrar o thread. Os blocos finalmente não executados são executados antes que o tópico seja abortado.

Usando Threadabort não é recomendado. É mau. Por que não usar outro mecanismo como um retevent (automático/manual)? Inicie o tópico com a tela de respingo, aguarde o evento. Se o outro código for feito carregando coisas, defina o evento em permitir que a tela de respingo feche a maneira normal (agradável).

Alguns pontos. A exceção do Threadabort é a razão pela qual o fio aborta. Não é um efeito colateral de você chamar o aborto. Quando você liga para abortar em um thread, o tempo de execução força uma exceção do Threadabort a ser propagada ao thread. Essa exceção pode ser capturada porque permite ao usuário executar alguma limpeza antes que o thread aborte.

A exceção é repensada automaticamente para garantir que o thread seja abortado. Se a exceção fosse capturada e se não fosse repensar, o fio nunca abortaria.

Design realmente inteligente, na verdade.

Portanto, não há problema em pegar essa exceção. Na verdade, você deveria. Mas pegue apenas essa exceção específica e não a exceção geral. (como mostrado abaixo)

catch(ThreadAbortException ex)
{
   //This is an expected exception. The thread is being aborted
}

Alterar o tipo de exceção para ThreadAborTexception e adicione uma chamada para Resetabort ()

    try
    {
        Program.splashThread.Abort();
    }
    catch(ThreadAbortException ex)
    {
        Thread.ResetAbort();
    }

Em geral, os threads abortados são considerados práticas muito ruins e podem levar a todos os tipos de bugs difíceis de rastrear. Você já pensou em descobrir uma maneira de apenas Feche a janela do Splash ou use algum tipo de votação Para parar o tópico quando uma bandeira foi definida?

Por que você faria isso? Basta definir uma bandeira que as pesquisas de encadeamento e, eventualmente, quando o thread o pegar, ele se fechará.

Experimente este código. Está funcionando bem para mim.

void splash()
{
    try {
        SplashScreen.SplashForm frm = new SplashScreen.SplashForm();
        frm.AppName = "HR";

        Application.Run(frm);
    }
    catch (ThreadAbortException ex)
    {
        Thread.ResetAbort();
    }
}

Eu usei a solução sugerida por Fredrik Mörk. É muito claro e elegante. Caso contrário, encontrei um problema se instanciarmos o formulário Splash antes de lançar o aplicativo real (Application.run (Mainform ...)):

Ele levanta uma concepção de invalidoPration causada pela manutenção de formulários ainda não existe no thread de chamadas. Para criar o identificador diretamente no thread t (e pule esta exceção!), Tente iniciar a forma de respingo dessa maneira:

Thread t = new Thread(new ThreadStart(delegate
{
    _splash = new Splash();
     Application.Run(_splash);
}));

t.Start();

E, se você planeja chamar o método Closesplash em mais ramos do programa, force o valor nulo após a primeira chamada:

    private static Splash _splash = null;
    public static void CloseSplash()
    {
        if (_splash!= null)
        {
            _splash.CloseSplash();
            _splash=null;
        }
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top