Tuesday, April 24, 2007 10:45 AM

Estava querendo publicar algum trecho de código para testar meu recém instalado addin do Windows Live Writer: Code formatter.

Finalmente arrumei uma desculpa ;)

Outro dia estava querendo começar um projeto pessoal de uma aplicação que rodaria no SysTray[1]. Eu sabia que o .Net Framework tinha alguma funcionalidade para isto, então procurei na internet alguns exemplos.

ncontrei vários exemplos de aplicativos WinForms que eram minimizados no SysTray. Não era isto o que eu estava querendo. Meu aplicativo irá rodar na SysTray e não precisava ser um Winforms, portanto queria criar o executável mais fino possível.

Com ajuda de poucos links (ver referências) que achei e algum improviso cheguei à seguinte solução.

  • Criei um novo projeto do tipo Class Library, que é o mais simples de todos.
  • Adicionei a referência à biblioteca System.Windows.Forms
  • Adicionei a referência à biblioteca System.Drawing
  • Criei uma classe herdando da classe ApplicationContext
  • Implementei seu construtor criando um novo objeto do tipo NotifyIcon, associando um ícone qualquer a propriedade Icon e setando a propriedade Visible para true
  • Nesta mesma classe criei um método Main para ser o ponto de entrada da aplicação, que simplesmente chama o método Application.Run() passando como parâmetro uma nova instância da classe.
  • Por último, alterei as propriedades do projeto para estabelecer o ponto de entrada da aplicação. Tenho que alterar o output type do projeto para Windows application e apontar o Startup object para minha classe (Veja a Figura 1).


Figura 1
: Alterando as propriedades do meu projeto

 

Até o momento todo o código do meu projeto é uma classe (Listagem 1). Se você rodar a aplicação o ícone aparece no SysTray. Mais nada acontece, porque não coloquei nenhuma funcionalidade na aplicação.


Listagem 1
: A aplicação SysTray

    public class AXPowerToolApplication : ApplicationContext
    {
        [STAThread]
        private static void Main()
        {
            Application.Run(new AXPowerToolApplication());
        }

        NotifyIcon sysTrayApplication;

        public AXPowerToolApplication()
        {
            sysTrayApplication = new NotifyIcon();
            sysTrayApplication.Icon = new Icon(@"<whereIsMyIcon>\NTSVC.ICO");
            sysTrayApplication.Visible = true;
        }
    }

Ok, consegui publicar um trecho de código-fonte, estou feliz :) Mas a solução está incompleta, não consigo nem fechar a porcaria da aplicação. Então vou trabalhar mais um pouquinho.

A primeira coisa que irei fazer é isolar minha aplicação da classe que tem o ponto de entrada. Crio uma nova classe que contém o NotifyIcon e que também vai criar um menu básico para minha aplicação. Esta classe, que está na Listagem 2, é minha interface com o usuário.


Listagem 2
: A nova classe que contém a minha interface com o usuário

    public class SysTrayApplication
    {
        private NotifyIcon notify;
        private ContextMenuStrip menu;

        public bool Visible
        {
            get { return notify.Visible; }
            set { notify.Visible = value; }
        }

        public SysTrayApplication()
        {
            notify = new NotifyIcon();
            InitIcon();
            InitMenu();
        }

        private void InitIcon()
        {
            notify.Icon = new Icon(@"<WhereIsMyIcon>\NTSVC.ICO");
        }

A interação com o usuário será através de um menu de contexto, como na maioria das aplicações de SysTray. O método InitMenu() cria um novo menu do tipo ContextMenuStrip e inclui um item no menu, que é o “Close”. Para esta tarefa eu poderia usar o ContextMenu, que é mais simples, porém tenho outras intenções para meu projeto que exigem um menu mais poderoso.


Listagem 3: Criando o menu

        private void InitMenu()
        {
            menu = new ContextMenuStrip();
            menu.SuspendLayout();

            ToolStripMenuItem closeMenu = new ToolStripMenuItem();
            closeMenu.Text = "Close";
            closeMenu.Click += new EventHandler(closeMenu_Click);

            menu.Items.Add(closeMenu);
            menu.ResumeLayout();

            notify.ContextMenuStrip = menu;
        }

        public void Close()
        {
            Application.Exit();
        }

        void closeMenu_Click(object sender, EventArgs e)
        {
            Close();
        }

Por último altero minha classe "ponto de entrada" para simplesmente instanciar um novo objeto da classe criada.


 Listagem 4: O ponto de entrada da aplicação

    public class AXPowerToolApplication : ApplicationContext
    {
        [STAThread]
        private static void Main()
        {
            Application.Run(new AXPowerToolApplication());
        }

        SysTrayApplication sysTrayApplication;

        public AXPowerToolApplication()
        {
            sysTrayApplication = new SysTrayApplication();
            sysTrayApplication.Visible = true;
        }
    }

O resultado final é uma aplicação puramente SysTray utilzando um menu como interface com o usuário. Com a evolução dela, talvez eu volte a mostrar mais algumas coisinhas.


Referências:

Writing a pure SysTray Application without a Window - Gerhard Stephan

[1] SysTray é aquela barrinha à direita onde fica o relógio, o MSN e outros aplicativos que rodam durante um tempo longo.

< Exemplos >

Comments

No comments posted yet.
Post Comment
Title *
Name *
Email (never displayed)
Website
Comment * (Allowed tags: blockquote, a, strong, em, p, u, strike, super, sub, code)  
Please add 1 and 5 and type the answer here: