domingo, 20 de fevereiro de 2011

Recursos do Windows 7 para WPF

Com a chegada do Windows 7 vários novos recursos foram disponibilizados aos desenvolvedores. Preview da janela,Aero Peak botões de controle na barra de tarefas e notificações diretamente no ícone.
Logo no lançamento do Windows 7 era bastante complicado, se perdia muito tempo aprendendo as novas API do SDK com wrappers para o WPF. Realmente perdíamos bastante tempo mesmo que fosse apenas pra colocar um botão no Preview da barra de tarefas.
Com a chegada do WPF 4 isso tudo ficou muito mais fácil. Através da propriedade TaskbarItemInfo da Window podemos ter acesso a esta grande API do Windows 7 e aprimorar ainda mais a experiência do usuário.
TaskbarItemInfo
Esta propriedade permite que possamos interagir com o ícone da nossa aplicação na barra de tarefas. As seguintes propriedades nos proporcionam essa facilidade:
  • Description: Descrição que aparecerá acima do Preview do Aero Peak.
  • Overlay: Define uma imagem que aparecerá na mesma posição do ícone da barra de tarefas. Isso nos permite mostrar informações mesmo quando a aplicação está no plano de fundo e o usuário está executando outras ações em outros programas.
  • ThumbnailClipMargin: Se não quisermos mostrar no Aero PeakPreview parcial do Video Player a visualização completa de nossa aplicação podemos definir através dessa propriedade qual parte deve ser mostrada no Preview.
    • ProgressState: Indica o estado da aplicação. Podemos definirVisual Studio após carregar um projeto esta propriedade de modo que avise o usuário que está sendo processada uma tarefa em tempo indeterminado, que ocorreu um erro ou a aplicação está parada e requer sua atenção.
    • ProgressValue: Utilizada quando se sabe o progresso de umaProgresso de Download no Internet Explorer atividade e se quer mostrar na barra de tarefas. É muito semelhante a um ProgressBar que não esteja sendo utilizado como Indeterminate.
    • ThumbButtonInfos: Aqui podemos colocar vários botões que,Botões de controle do Media Player através do Aero Peak, façam com que o usuário interaja com a aplicação mesmo ela estando no plano de fundo. Podem ser visualizados até 7 botões ao mesmo tempo.
    Fiz uma pequena aplicação conceito para aplicar tudo isso.Video Player Criei um Video Player que busca um vídeo via Streaming do Channel9. Utilizei o TaskbarItemInfo da seguinte forma:
    • Utilizei a barra de progresso na barra de tarefas para mostrar enquanto ainda está sendo feito buffer do vídeo.
    • Quando o vídeo começar a rodar coloco um Overlay na barra de tarefas semelhante a um botão Play.
    • Defini que no Preview do Aero Peak só mostraria a parte do vídeo e não os controles.
    • Adicionei um botão para fechar diretamente no Preview (eu sei, é redundante, mas é só pra mostrar o conceito).
    Para adicionar toda essa funcionalidade a minha aplicação não levei mais do que alguns minutos. Demora mais pra achar imagens legais e tal. Mas acho que deu pra entender a ideia. O XAML que tive que adicionar é o seguinte:
    <Window.TaskbarItemInfo> <TaskbarItemInfo x:Name="StatusTaskbarItemInfo" ProgressState="Indeterminate" Description="Video Player" ThumbnailClipMargin="15,54,17,75"> <TaskbarItemInfo.ThumbButtonInfos> <ThumbButtonInfo Description="Fechar" Click="ThumbButtonInfo_Click" ImageSource="...sua imagem aqui..."> </ThumbButtonInfo> </TaskbarItemInfo.ThumbButtonInfos> </TaskbarItemInfo> </Window.TaskbarItemInfo>
    O código do exemplo bem como uma aplicação pronta (ClickOnce) pode ser encontrados aqui.
    Enjoy

    domingo, 23 de janeiro de 2011

    WPF com Splash Screen

    Desde sempre estamos acostumados a aplicações que precisam de um tempo de espera relativamente grande para iniciar. Isso aconteceu e ainda acontece com aplicações WIN32 que ao iniciarem precisam de uma grande quantidade de arquivos carregados na memória.

    Já se foi o tempo onde o .NET era muito lento para carregar. Época em que tínhamos computadores com menos de 1GB de RAM e apenas um processador e núcleo com menos de 1GHz. Não me refiro a aplicação rodando mas sim o tempo que demorava para carregar na memória as DLL do Framework e aplicação num Cold Start. Mas mesmo assim, hoje ainda não é instantâneo.

    Uma solução que aumenta a experiência do usuário éSplash Screen do Windows Live Writer a utilização de um Splash Screen, efeito muito utilizado por vários tipos de aplicações: Adobe Photoshop, NetBeans, Visual Studio, Windows Live Writer são alguns exemplos.

    Hoje vou mostrar como colocar um Splash Screen Splash Screen do Visual Studio 2010no WPF fazendo com a resposta ao usuário ao chamar a aplicação seja praticamente imediata.

    Desde a versão do Framework 3.5 SP1 existem 3 opções para se criar um Splash Screen no WPF. Em todas elas devemos lembrar que as imagens deve ser suportadas pelo Windows Imaging Component (WIC) e isso inclui: BMP, GIF, JPEG, PNG e TIFF.

    Se você utilizar uma imagem PNG com transparência ela será mostrada no Splash Screen com transparência. Se utilizar um GIF animado só será mostrado o primeiro frame.

    Opção 1: Adicionando o item SplashScreen

    Com certeza esta é a opção mais simples.

    • No menu de contexto do seu projeto selecione a opção Add e depois New Item.
    • Selecione o item SplashScreen (WPF) e escolha um nome para o mesmo.
    • Rode a aplicação e veja como ficou a imagem padrão de Splash Screen.
    Opção 2: Utilizando uma imagem com Build Action SplashScreen

    A segunda opção não consiste em algo tão mais complexo do que o item SplashScreen, na verdade se utiliza o mesmo recurso utilizado por ele, uma imagem que tem definido seu Build Action como SplashScreen.

    • No menu de contexto do seu projeto selecione a opção Add e depois Existing Item.
    • Selecione uma imagem que queira que apareça enquanto a sua aplicação está fazendo o carregamento mais pesado.
    • Vá na aba das propriedades desta imagem e configure o Build Action para SplashScreen.
    • Rode a aplicação e veja como ficou a imagem selecionada como Splash Screen da sua aplicação.
    Opção 3:Utilizando as APIs de SplashScreen

    Podemos utilizar a API de SplashScreen através da classe de mesmo nome.

    Não existem passos mágicos a seguir, apenas devemos prestar atenção que a imagem que quisermos utilizar deve ter seu Build Action configurado para Resource.

    public partial class MainWindow : Window { public MainWindow() { var splash = new SplashScreen("Splash.png"); splash.Show(false); splash.Close(TimeSpan.FromSeconds(3)); InitializeComponent(); } }

    Como podemos ver, basta instanciar a classesplash SplashScreen passando o caminho do Resource.

    Depois chamamos o método Show para mostrar a imagem e informamos que a mesma não deverá ser fechada automaticamente.

    Por fim definimos através do método Close que após 3 segundos ela sofrerá um efeito fade out e fechará.

    O Splash Screen em si não faz a aplicação ficar mais rápida para abrir, mas como faz uso do Windows Imaging Component (WIC) ele mostra a imagem muito antes da aplicação carregar. Com isso melhora a experiência do usuário com a sua aplicação.

    Enjoy

    quinta-feira, 30 de dezembro de 2010

    Sabe o que é modificador internal? Sabe mesmo???

    Pois é, o post começa com algo bem básico do C#, coisa do primeiro dia de aula mesmo: Modificadores de Acesso. Só pra relembrar:

    • public : Sem restrição de acesso.
    • protected : Acessado pela classe que o define e pelas classes derivadas dela.
    • internal : Acessado apenas de dentro do mesmo assembly.
    • private : Acessado somente de dentro da classe (mesmo se forem instancias diferentes).

    Isso todo mundo já sabe (ou deveriam saber). O ponto em que quero chegar é que, dizer que "membros ou tipos internal só podem ser acessados dentro do mesmo assembly" não é uma completa verdade.

    InternalsVisibleToAttribute

    O atributo InternalsVisibleTo introduz ao assembly o conceito de Friend Assembly. Com isto os membros ou tipos marcados com o modificador de acesso internal podem ser acessados de outro assembly. Vamos ver como funciona:

    Nesta solução podemos ver que existem 3 Projetoprojetos, sendo 2 projetos do tipo ClassLibrary e 1 ConsoleApplication.

    Adicionamos o projeto AssemblyA como referencia no projeto MyConsoleApplication. Depois o projeto AssemblyB como referencia no projeto AssemblyA e MyConsoleApplication.

    Ele ficará como a imagem ao lado. Podemos ver que existem algumas classes já declaradas.

    No AssemblyB temos uma classe com modificador de acesso internal e outra com o modificador de acesso public (Como dizem os nomes).

    Agora vamos tentar instanciar a classe AssemblyB.MyInternalClass de dentro da cBuild Faillasse AssemblyA.MyPublicUtilClass e compilar a aplicação para ver o que acontece.

    O Visual Studio não deixa compilar a aplicação. Ele nos mostra o motivo do build failed em duas mensagens de erro:

    1. O tipo AssemblyB.MyInternalClass não tem construtor definido.
    2. O tipo AssemblyB.MyInternalClass não é acessível devido ao seu nível de proteção.

    Como a classe está definida com o seu modificador de acesso sendo internal o Visual Studio segue a regra que descrevemos mais acima e não deixa ela ser acessada (no caso instanciada).

    Esses mesmos dois erros ocorreriam se tivéssemos tentado o acesso a esta classe no assembly MyConsoleApplication.

    Nesse momento entra em ação o atributo InternalsVisibleTo que faz uma alteração a nível de assembly fazendo com que AssemblyA possa instanciar a classe em questão.

    Segue o trecho que pode ser colocado em qualquer arquivo de código mas que por boas práticas deve ser colocado no arquivo AssemblyInfo da pasta Properties do projeto.

    AssemblyInfo

    Com isto compilamos novamente a aplicação e podemos ver que agora temos acesso a classe MyInternalClass de dentro do assembly AssemblyA.

    Também podemos verificar que apesar do acesso a classe MyConsoleApplicationMyInternalClass ter sido alterado em relação ao assembly AssemblyA, o assembly MyConsoleApplication ainda continua ser ter acesso. Se fosse necessário que o assembly MyConsoleApplication pudesse acessar também a classe MyInternalClass bastaria colocar mais um atributo (permite múltiplos) no AssemblyInfo especificando isto.

    Considerações Importantes

    Não são muitos os casos onde é aconselhada esta prática. Ela é exigida em casos onde a organização do projetoSistem.Workflow.Activities a exige:

    • Casos onde existe um projeto de teste e é necessário o acesso a membros internal para o teste.
    • Quando se desenvolve um ClassLibrary que é composto por vários assemblies mas requerem acesso a membros existentes entre eles. Este é o caso do assembly System.Workflow.Activities.

    O exemplo que implementei foi o de mais fácil compreensão. Existem algumas regras que devem ser seguidas para a utilização desde atributo. A regra mais importante é a respeito dos Strong Names:

    • Se o assembly que se quer ter os membros internal visíveis tiver um strong name o assembly que o consumirá também deverá ter. No atributo InternalsVisibleTo deverá constar, separados por vírgula, o nome do assembly mais a public key dentro da string que é passada ao construtor.
    • Se o assembly que se quer ter os membros internal visíveis não tiver um strong name o assembly que o consumirá também não deverá ter.

    Enjoy