Pergunta

Eu tenho um aplicativo de formulário do Windows que utiliza uma classe compartilhada para abrigar todos os objetos comuns de aplicação. A classe de configurações tem uma coleção de objetos que fazem coisas periodicamente, e então há algo de interesse, eles precisam alertar o formulário principal e tê-lo actualizado.

Atualmente estou fazendo isso por meio de eventos nos objetos, e quando cada objeto é criado, eu adicionar um EventHandler para mapeia a volta do evento para o formulário. No entanto, eu estou correndo em alguns problemas que sugere que estes pedidos não são sempre terminando na cópia principal do meu formulário. Por exemplo, a minha forma tem um ícone na bandeja de notificação, mas, quando as capturas de forma e evento e tenta exibir uma bolha, nenhuma bolha aparece. No entanto, se eu modificar esse código para tornar o ícone visível (embora ele já é), e em seguida, exibir a bolha, um segundo ícone aparece e exibe a bolha corretamente.

Alguém correr para isso antes? Existe uma maneira que eu possa forçar todos os meus eventos a serem capturados pela única instância do formulário, ou se existe uma maneira completamente diferente de lidar com isso? Eu posso postar amostras de código, se necessário, mas eu estou pensando que é um problema de threading comum.

MAIS INFORMAÇÕES: Eu estou usando atualmente Me.InvokeRequired no manipulador de eventos no meu formulário, e ele sempre retorna FALSE neste caso. Além disso, o segundo ícone da bandeja criado quando eu torná-lo visível a partir deste formulário não tem um menu de contexto sobre ele, enquanto o ícone "real" faz? - faz que qualquer indício em

Eu vou puxar o meu cabelo para fora! Isso não pode ser tão difícil!

Solução : Graças a nobugz para a pista, e ele me levar ao código que estou usando agora (que funciona muito bem, embora eu não posso deixar de pensar que há uma maneira melhor de fazer isso ). Eu adicionei uma variável boolean privado para o formulário chamado "IsPrimary", e acrescentou o seguinte código para o construtor forma:

    Public Sub New()
        If My.Application.OpenForms(0).Equals(Me) Then
            Me.IsFirstForm = True
        End If
    End Sub

Uma vez que esta variável é definida e os acabamentos do construtor, ele dirige certo para o manipulador de eventos, e eu lidar com isso desta forma (ressalva: Desde a forma que eu estou procurando é a principal forma para a aplicação, My.Application .OpenForms (0) recebe o que eu preciso Se eu estava olhando para a primeira instância de uma forma não-inicialização, eu teria que percorrer até que eu achei):.

    Public Sub EventHandler()
        If Not IsFirstForm Then
            Dim f As Form1 = My.Application.OpenForms(0)
            f.EventHandler()
            Me.Close()
        ElseIf InvokeRequired Then
            Me.Invoke(New HandlerDelegate(AddressOf EventHandler))
        Else
            ' Do your event handling code '
        End If
    End Sub

Em primeiro lugar, ele verifica para ver se ele está em execução na forma correta - se não é, em seguida, chamar a forma correta. Em seguida, ele verifica para ver se o segmento está correta, e chama o segmento interface do usuário, se não é. Em seguida, ele executa o código do evento. Eu não gosto que é potencialmente três chamadas, mas eu não consigo pensar em outra maneira de fazê-lo. Parece que funciona bem, mas é um pouco complicado. Se alguém tiver uma maneira melhor de fazer isso, eu adoraria ouvi-lo!

Mais uma vez, obrigado por toda a ajuda - isso iria conduzir-me louco

Foi útil?

Solução

Eu acho que é um problema de threading também. Você está usando Control.Invoke () no seu manipulador de eventos? .NET normalmente pega violações quando você depurar o aplicativo, mas há casos em que não pode. NotifyIcon é um deles, não há nenhum identificador de janela para verificar afinidade de segmento.

Editar após OP mudou pergunta:

Um clássico VB.NET armadilha é a referência a um exemplo Forma pelo seu nome tipo. Como Form1.NotifyIcon1.Something. Isso não funciona como esperado quando você usa threading. Ele vai criar uma new instância da classe Form1, não usar a instância existente. Essa instância não é visível (Show () nunca foi chamado) e é de outra maneira mortinho da silva, uma vez que está sendo executado no segmento que não bombeia um loop de mensagem. Vendo um segundo ícone aparecer é um dar-away morto. Então, está ficando InvokeRequired = false quando você sabe que você está usando-o por um fio.

Você deve usar uma referência para a instância de formulário existente. Se isso é difícil passar por aqui (você costuma passar "Me" como um argumento para o construtor da classe), você pode usar Application.OpenForms:

  Dim main As Form1 = CType(Application.OpenForms(0), Form1)
  if (main.InvokeRequired)
    ' etc...

Outras dicas

Use Control.InvokeRequired para determinar se você está no segmento apropriado, em seguida, usar Control.Invoke se você não é.

Você deve olhar para a documentação para o método Invoke no formulário. Ele irá permitir que você faça o código que atualiza a forma de execução no segmento que possui o formulário, (o que deve fazer, formas do Windows não são thread-safe). Algo como Delegado Private Sub UpdateStatusDelegate (ByVal NEWSTATUS como String)

sub Pública UpdateStatus (ByVal NEWSTATUS como String) Se Me.InvokeRequired Então Dim d Como Nova UpdateStatusDelegate (AddressOf UpdateStatus) Me.Invoke (d, new Object () {} NEWSTATUS) Outro 'Atualizar o status de forma End If

Se você fornecer um código de exemplo que eu ficaria feliz em fornecer um exemplo mais adaptado.

Editar após OP disse que eles estão usando InvokeRequired.

Antes de chamar InvokeRequired, verifique se a alça de formulário foi criado, há uma propriedade HandleCreated Eu acredito. InvokeRequired sempre retorna false se o controle não tem atualmente uma alça, isso significa então o código não é thread mesmo seguro que você tenha feito a coisa certa a fazer assim. Atualizar a sua pergunta quando você descobrir. Um código de exemplo seria útil também.

em c # parece que isso:

private EventHandler StatusHandler = new EventHandler(eventHandlerCode)
void eventHandlerCode(object sender, EventArgs e)
    {
        if (this.InvokeRequired)
        {
            this.Invoke(StatusHandler, sender, e);
        }
        else
        {
          //do work
        }
    }
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top