none
Winforms Mdi MdiChild Modal RRS feed

  • Pergunta

  • Como faço para somente ter uma instancia de um formulário filho dentro de MDI? Gostaria também que esse formulário filho fosse modal.

    Att,

    Ricardo

    Ricardo Novais
    sábado, 4 de julho de 2009 00:04

Respostas

  • Olá Ricardo,

    A solução mais comum para esse tipo de problema, é guardar uma referência para o formulário a ser instanciado em uma variável da sua classe, que você pode utilizar para controlar se já existe ou não uma instância. Algo como:

    // Variável da classe que guarda a referência para 
    // o formulário aberto (se estiver, caso contrário, null)
    private FormFilho formFilho;
    
    private void MenuItem_Click(object sender, RoutedEventArgs e)
    {
        // O formulário já está aberto?
        if (this.formFilho != null)
        {
            // Sim. Então apenas deixe-o ativo (foco)
            this.formFilho.Activate();
        }
        else
        {
            // Não. Então vamos abrir e guardar a referência
            this.formFilho = new FormFilho();
    
            // Vamos reinicializar a variável quando o formulário for fechado
            this.formFilho.Closed += delegate { this.formFilho = null; };
    
            // Mostra o formulário
            this.formFilho.Show();
        }
    }

    Outra solução muito parecida, é desabilitar o botão (ou item de menu) que abre o formulário, e só voltar a habilitá-lo quando o formulário fechar... Algo mais ou menos assim:

    // Desabilita o botão (ou item de menu) que abre este formulário
    this.botaoQueAbreEsteForm.Enabled = false;
    
    // Instancia o formulário como sendo "filho" do MDI
    var f = new FormFilho();
    f.MdiParent = this;
    
    // Volta a habilitar o item de menu apenas quando o formulário fechar
    f.Closed += delegate { this.botaoQueAbreEsteForm.Enabled = true; };
    
    // Mostra o formulário
    f.Show();
    


    Por fim, se o formulário puder ser aberto de diferentes lugares, e desabilitar todos os botões/itens de menu ficar complicado, então acredito que a sugestão do Robson seja a ideal, procurando pelo formulário na lista de formulários instanciados, para decidir se deve ou não criar uma nova instância...

    Nesse caso, e apenas para complementar, pode economizar algumas linhas de código utilizando uma query LINQ para procurar o formulário... O resultado é o mesmo:

    // Procura o formulário na lista de formulários filhos instanciados
    var f = this.MdiChildren.OfType<FormFilho>().FirstOrDefault();
    
    // Não encontrou?
    if (f == null)
    {
        // Não... Então cria a instância e mostra.
        f = new FormFilho();
        f.MdiParent = this;
        f.Show();
    
        return;
    }
    
    // Se chegou até aqui, é porque o formulário já existia...
    // Sim. Então apenas deixe-o ativo (foco)
    f.Focus();
    


    Por fim, se você tem uma quantidade muito grande de formulários em sua aplicação, que só devem ter uma instância aberta de cada vez, pode considerar a criação de uma classe só para isso (FormLoader)... Verificar, instanciar e mostrar formulários. Dê uma olhada no exemplo do Roy Osherove:

    Problem & Solution: Allow only one instance of any MDI child form in your MDI application
    http://weblogs.asp.net/rosherove/archive/2004/06/16/156933.aspx


    Abraços,
    Caio Proiete



    Caio Proiete
    Microsoft MVP, MCT, MCPD, MCTS, MCSD
    http://www.caioproiete.com

    segunda-feira, 6 de julho de 2009 00:39
    Moderador
  • Ricardo,

    Não sei se existe forma mais simples de se fazer mas pode ser assim: no form pai, no item de menu que chama o form filho, coloque o codigo abaixo.


    FrmTeste frmTeste = null; // form a ser aberto

    // procura form na relacao de forms filhos
    foreach(Form frm in this.MdiChildren)
    {
          // se encontrou inicializa instancia de frmTeste com o form ja aberto
          if (frm is FrmTeste)
          {
               frmTeste = (FrmTeste)frm;
               break;
          }
    }

    // se nao encontrou na relacao, instancia objeto, "seta" form pai e exibe form
    if (frmTeste == null)
    {
        frmTeste = new FrmTeste();
        frmTeste.MdiParent = this;
        frmTeste.Show();
    }

    // garante que ele fique em foco caso haja outros forms abertos
    frmTeste.Focus();

    ----------

    []s
    Robson Castilho - MCTS .Net 2.0 Windows/Web Applications [Se o post foi útil, não esqueça de marcá-lo. Obrigado]
    sábado, 4 de julho de 2009 15:23

Todas as Respostas

  • Da uma olhada aqui

    http://social.msdn.microsoft.com/Forums/pt-BR/clientept/thread/869b8084-8cc8-4620-ac3a-57af6eebaf70

    Agora ter um Filho modal nunca tentei... mesmo pq nao faz muito sentido... pq o Modal teria q ficar sobre o Pai...
    Se não funciona de um jeito, tente de outro totalmente diferente ^_^
    sábado, 4 de julho de 2009 02:08
    Moderador
  • Rui, o formulário já está sendo chamado e mostrado dentro do formulário mdi, acontece é que cada vez que eu clico é criada uma nova instancia desse formulário, o que eu quero é que se não existe uma instancia desse formulário ele cria, senão mostra a instancia já criada.

    Att,

    Ricardo
    Ricardo Novais
    sábado, 4 de julho de 2009 12:17
  • Ricardo,

    Não sei se existe forma mais simples de se fazer mas pode ser assim: no form pai, no item de menu que chama o form filho, coloque o codigo abaixo.


    FrmTeste frmTeste = null; // form a ser aberto

    // procura form na relacao de forms filhos
    foreach(Form frm in this.MdiChildren)
    {
          // se encontrou inicializa instancia de frmTeste com o form ja aberto
          if (frm is FrmTeste)
          {
               frmTeste = (FrmTeste)frm;
               break;
          }
    }

    // se nao encontrou na relacao, instancia objeto, "seta" form pai e exibe form
    if (frmTeste == null)
    {
        frmTeste = new FrmTeste();
        frmTeste.MdiParent = this;
        frmTeste.Show();
    }

    // garante que ele fique em foco caso haja outros forms abertos
    frmTeste.Focus();

    ----------

    []s
    Robson Castilho - MCTS .Net 2.0 Windows/Web Applications [Se o post foi útil, não esqueça de marcá-lo. Obrigado]
    sábado, 4 de julho de 2009 15:23
  • Olá Ricardo,

    A solução mais comum para esse tipo de problema, é guardar uma referência para o formulário a ser instanciado em uma variável da sua classe, que você pode utilizar para controlar se já existe ou não uma instância. Algo como:

    // Variável da classe que guarda a referência para 
    // o formulário aberto (se estiver, caso contrário, null)
    private FormFilho formFilho;
    
    private void MenuItem_Click(object sender, RoutedEventArgs e)
    {
        // O formulário já está aberto?
        if (this.formFilho != null)
        {
            // Sim. Então apenas deixe-o ativo (foco)
            this.formFilho.Activate();
        }
        else
        {
            // Não. Então vamos abrir e guardar a referência
            this.formFilho = new FormFilho();
    
            // Vamos reinicializar a variável quando o formulário for fechado
            this.formFilho.Closed += delegate { this.formFilho = null; };
    
            // Mostra o formulário
            this.formFilho.Show();
        }
    }

    Outra solução muito parecida, é desabilitar o botão (ou item de menu) que abre o formulário, e só voltar a habilitá-lo quando o formulário fechar... Algo mais ou menos assim:

    // Desabilita o botão (ou item de menu) que abre este formulário
    this.botaoQueAbreEsteForm.Enabled = false;
    
    // Instancia o formulário como sendo "filho" do MDI
    var f = new FormFilho();
    f.MdiParent = this;
    
    // Volta a habilitar o item de menu apenas quando o formulário fechar
    f.Closed += delegate { this.botaoQueAbreEsteForm.Enabled = true; };
    
    // Mostra o formulário
    f.Show();
    


    Por fim, se o formulário puder ser aberto de diferentes lugares, e desabilitar todos os botões/itens de menu ficar complicado, então acredito que a sugestão do Robson seja a ideal, procurando pelo formulário na lista de formulários instanciados, para decidir se deve ou não criar uma nova instância...

    Nesse caso, e apenas para complementar, pode economizar algumas linhas de código utilizando uma query LINQ para procurar o formulário... O resultado é o mesmo:

    // Procura o formulário na lista de formulários filhos instanciados
    var f = this.MdiChildren.OfType<FormFilho>().FirstOrDefault();
    
    // Não encontrou?
    if (f == null)
    {
        // Não... Então cria a instância e mostra.
        f = new FormFilho();
        f.MdiParent = this;
        f.Show();
    
        return;
    }
    
    // Se chegou até aqui, é porque o formulário já existia...
    // Sim. Então apenas deixe-o ativo (foco)
    f.Focus();
    


    Por fim, se você tem uma quantidade muito grande de formulários em sua aplicação, que só devem ter uma instância aberta de cada vez, pode considerar a criação de uma classe só para isso (FormLoader)... Verificar, instanciar e mostrar formulários. Dê uma olhada no exemplo do Roy Osherove:

    Problem & Solution: Allow only one instance of any MDI child form in your MDI application
    http://weblogs.asp.net/rosherove/archive/2004/06/16/156933.aspx


    Abraços,
    Caio Proiete



    Caio Proiete
    Microsoft MVP, MCT, MCPD, MCTS, MCSD
    http://www.caioproiete.com

    segunda-feira, 6 de julho de 2009 00:39
    Moderador