Como Abrir Objetos Encapsulados em Assemblies Externos no WPF

Outra dúvida comum entre os desenvolvedores que estão iniciando refere-se a como podemos encapsular e consumir objetos (Janelas, Páginas e Imagens) em assemblies externos. Esta prática é comum e muito útil para você organizar seu projeto.



Por exemplo, em todas as aplicações, por mais simples que sejam, utilizamos imagens (ícones) para construir nossa interface com o usuário. Muitas vezes, encontro projetos nos quais os desenvolvedores utilizaram um mesmo conjunto de imagens, mas de uma forma inadequada, ou seja, copiando uma pasta de imagens em todos os projetos que precisavam. Isso cria uma poluição de arquivos de imagens que poderiam ser compartilhados através de uma biblioteca encapsulada num assembly.


Outro cenário comum é a necessidade de modularizarmos nosso projeto. Além das bibliotecas de códigos (nossas classes) que com maior frequência encontramos corretamente encapsuladas em assemblies, os desenvolvedores têm dúvidas quando precisam encapsular objetos da interface como Janelas (Window) e Páginas (Page).



Essas dúvidas não se limitam aos desenvolvedores WPF, são comuns também entre os desenvolvedores que trabalham com Windows Forms, principalmente quando se faz necessário implementar o conceito Late Biding. Mas isto é assunto para outro artigo na seção Windows Forms.


 Neste artigo vou demonstrar como encapsular e consumir imagens, janelas e páginas em assemblies externos. Então preste atenção, e mãos-a-obra. A Figura 1 apresenta a interface do nosso exemplo. Este exercício consiste em criar uma Janela com um TabControl e alguns botões. Ao clicar nos três primeiros botões, o aplicativo deverá criar um novo TabItem e exibir a página correspondente ao botão clicado. Os objetos Page estão encapsulados num assembly externo que originalmente chamei de ObjetosExternos.dll. O método AbrirPagina que ilustra esta funcionalidade, também demonstra como verificar se a página desejada já está carregada no TabControl, neste caso, o aplicativo apenas seleciona o TabItem correspondente.





Figura 1: Carregando Páginas e Janelas Externas



O botão btnAbrirJanelaExterna carrega um objeto Window, chamado JanelaExemploImagem, também encapsulado no mesmo assembly externo. Esta janela apresenta um objeto Image e três botões. Ao clicar em cada botão, a imagem exibida no controle Image é alterada. As imagens utilizadas também estão armazenadas num assembly externo chamado BibliotecaImagens.dll. Veja a Figura 2.




Figura 2: Carregando Imagens Externas


Para a Solução deste exemplo, foram criados três projetos: BibliotecaImagens, ExemploAbrindoObjetosExternos e ObjetosExternos. A Figura 3 apresenta a janela Solution Explorer.


 


Figura 3: A janela Solution Explorer


Desvio de percurso


E apenas para não perder a oportunidade, o último botão da janela principal deste exemplo, ilustra como encerrar nossa aplicação de forma explícita. Para isto, o arquivo App.xaml deve apresentar o parâmetro ShutdownMode com o valor OnExplicitShutdown, como mostra a Figura 4.



Figura 4: Definindo o ShutdownMode no arquivo App.xaml



O código associado ao botão btnSairExemplo está apresentado no Quadro 1, logo abaixo:


private void btnSairExemplo_Click(object sender, RoutedEventArgs e)
{
   Application.Current.Shutdown();
}


Quadro 1: O método Shutdown()



Voltando aos Assemblies Externos


O método AbrirPagina() será o primeiro a ser explicado. Este método requer três parâmetros, apresentados abaixo:


 


Assembly

Nome do Assembly Externo que contém o objeto Page desejado. Neste exemplo o assembly que contém as páginas chama-se ObjetosExternos. Na prática, se você construir um assembly com Namespaces compostos, você deverá passar o Namespace completo neste parâmetro. Exemplo: DevBrasil.ObjetosExternos.Paginas.

NomePagina

Apenas o nome do objeto Page desejado. Exemplo: PaginaDevBrasil.

 

Titulo

Meramente ilustrativo, este parâmetro recebe uma string que será atribuída ao TabItem que acomodará a Página.



O código do método AbrirPagina() inicia verificando se a página solicitada já está carregada no TabControl. Se for encontrada, o TabItem que contém a página é selecionado. Quando a página não é encontrada, o método se encarrega de criar um novo TabItem para acomodar a nova página.


Cabe aqui explicar que os objetos Page não podem ser atribuídos diretamente ao TabItem, devemos criar um objeto Frame. A propriedade Source do objeto Frame é responsável por acomodar o objeto Page desejado. Posteriormente, o objeto Frame deve ser atribuído à propriedade Content do TabItem. É mais simples do que parece, e você pode conferir o código no Quadro 2.


private void AbrirPagina(string _Assembly, string _NomePagina, string _Titulo)
{
    tabConteudo.Items.Refresh();
 
    bool founded = false;
 
    try
    {
        Cursor = Cursors.Wait;
 
        foreach (TabItem item in tabConteudo.Items)
        {
            if (item.Name == “tab” + _NomePagina)
            {
                tabConteudo.SelectedItem = item;
                founded = true;
            }
 
            if (founded) break;
        }
 
        if (!founded)
        {
            TabItem newTab = new TabItem();
 
            newTab.Name = “tab” + _NomePagina.Replace(“/”string.Empty);
            newTab.Header = _Titulo;
 
            Frame NovaFrame = new Frame();
 
            NovaFrame.Background = Brushes.Gainsboro;
            NovaFrame.Source = new 
Uri(“pack://application:,,,/” + _Assembly + “;component/” + _NomePagina + “.xaml”UriKind.Absolute);
            newTab.Content = NovaFrame;
 
            this.tabConteudo.Items.Add(newTab);
 
            tabConteudo.SelectedItem = newTab;
 
        }
 
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message);
    }
    finally
    {
        Cursor = Cursors.Arrow;
    }
}













Quadro 2: Implementando o método AbrirPagina()


Para invocar o método AbrirPagina() você só precisa passar os parâmetros requeridos. O código apresentado a seguir demonstra como usar este método para abrir a página DevBrasil encapsulada no assembly ObjetosExternos.


private void btnDevBrasil_Click(object sender, RoutedEventArgs e)
{
    AbrirPagina(“ObjetosExternos”“PaginaDevBrasil”“DevBrasil”);
}













Quadro 3: Invocando o método AbrirPagina() 


O método AbrirJanela()


O próximo a ser analisado é o método AbrirJanela(). Neste método, usamos o objeto Type para obter uma instância da Janela desejada. Um teste lógico simples se encarrega de verificar se os parâmetros informados correspondem a um tipo existente, caso o método GetType retorne valor Nulo, o procedimento é abortado. Quando o objeto é válido, o método CreateInstance do objeto Activator é usado para instanciar a Janela. É necessário fazer um casting da nova instancia antes de atribuí-la para a variável do tipo Window. O Quadro 4 apresenta este método.


private void AbrirJanela(string _Assembly, string _NomeJanela)
{
    Type t = Type.GetType(_Assembly + “.” + _NomeJanela + “,” + _Assembly);
 
    if (t != null)
    {
        Window w = (Window)Activator.CreateInstance(t);
 
        w.WindowStartupLocation = WindowStartupLocation.CenterScreen;
 
        w.ShowDialog();
    }
}













Quadro 4: O método AbrirJanela()


Para invocar o método AbrirJanela() basta informar os dois parâmetros requeridos. Veja o exemplo a seguir.


private void btnAbrirJanelaExterna_Click(object sender, RoutedEventArgs e)
{
    AbrirJanela(“ObjetosExternos”“JanelaExemploImagem”);
}













Quadro 5: Invocando o método AbrirJanela()


Carregando Imagens Externas


Finalmente, vamos entender como atribuir uma imagem armazenada num assembly externo para a propriedade Source do controle Image. A classe Uri é utilizada para esta finalidade. Para entender melhor este conceito, pesquise na documentação do Visual Studio a expressão “Pack URIs in WPF”. Confira o código a seguir.


private void btnImagemSeattle_Click(object sender, RoutedEventArgs e)
{
    imgExemplo.Source = new BitmapImage(
new Uri(“pack://application:,,,/BibliotecaImagens;component/JPG/Seattle.jpg”));
}













Quadro 6: Carregando imagens externas


Conclusão


Neste artigo você aprendeu como encapsular e consumir imagens, janelas e páginas em assemblies externos. Aprofunde seus conhecimentos sobre este tema visitando a comunidade WPF.


Faça o download deste artigo no formato PDFe também do código-fonte deste exemplo.


 

Quarta Tecnológica em Sorocaba

Direcionada para os empresários e empreendedores do segmento de Tecnologia da Informação, a Prefeitura Municipal de Sorocaba realiza nesta quarta-feira, dia 23/02/2011, a Quarta Tecnológica. O evento é gratuito (vagas limitadas), será realizado no Auditório da Biblioteca Municipal “Jorge Guilherme Senger”, e abordará em seus dois temas principais, a Cultura da Inovação e Como e Onde Conseguir Recursos para Inovação. Para garantir sua reserva, ligue para (15) 3237-9087 ou envie e-mail para: michel.podisorocaba@gmail.com.