Jump to content

Recommended Posts

Posted

Boa noite estou com um problema que pode ser simples para quem já esteja com um conhecimento mais em C# a dúvuda é:

Fiz uma tela em C# que tem dois botões Star e Stop, quando eu clico em Start ele executa esse código abaixo

private void b_Play_Click(object sender, EventArgs e)

{

  FicarEmLoop = true; //Seta o Loop no programa

  lbl_Executando.Visible = true;

  lbl_Parado.Visible = false;

  b_Play.Enabled = false;

  b_Stop.Enabled = true;

      while (FicarEmLoop)

      {

          //EXECUTA MEUS COMANDOS...

      }

}

Só que assim, a qualquer momento eu quero clicar e atualizar a variavel FicarEmLoop com  false quando clicar em Stop, só que o programa não deixa pois está no meio do loop ainda, existe solução para isso?, esse é meu bloco do botão Stop.

private void b_Stop_Click(object sender, EventArgs e)

{

    FicarEmLoop = false; // Para o loop no programa

}

Preciso poder clicar no botão, o que posso fazer?

Abraço a todos

Posted

O problema é simples, o windows forms controlo de aspecto gráfico da plataforma .NET tal como o Swing do java apenas usa uma thread para actualizar o estado da componente gráfica de uma aplicação, ou seja, todos os eventos gerados por acções da parte gráfica são corridos numa só thread, logo se bloqueias essa thread a tua parte gráfica deixa de funcionar.

Sugiro-te o uso da class BackgroundWorker para pores esse teu loop a correr numa outra thread.

Cump<

Posted

Boas...

Já agora, aproveito também para tirar umas dúvidas e conhecer as vossas opiniões! :-) A utilização do Application.DoEvents() parece-me ser bastante simples, o que é bom. No entanto, o loop continua a ser executado na thread do GUI o que pode levar a que o form fique "congelado" e o botão Stop inacessível.

Eu faria algo como o DVD sugeriu, mas usaria a TheadPool, por achar mais simples. Algo assim:

using System;
using System.Windows.Forms;
using System.Threading;

namespace Tests
{
    public partial class Form1 : Form
    {
        private object lockObject = new object();
        private bool isInLoop = true;
        private bool IsInLoop
        {
            get 
            {
                lock (lockObject)
                {
                    return isInLoop;
                }
            }
            set 
            {
                lock (lockObject)
                {
                    isInLoop = value;
                }
            }
        }

        public Form1()
        {
            InitializeComponent();
            btnStop.Enabled = false;
        }

        private void btnStop_Click(object sender, EventArgs e)
        {
            btnStop.Enabled = false;
            btnPlay.Enabled = true;
            IsInLoop = false;
        }

        private void btnPlay_Click(object sender, EventArgs e)
        {
            btnPlay.Enabled = false;
            btnStop.Enabled = true;
            IsInLoop = true;
            ThreadPool.QueueUserWorkItem(ExecuteMyAppLogic);            
        }
        
        private void ExecuteMyAppLogic(object state)
        {
            while (IsInLoop)
            {
                // Executar a lógica da aplicação
            }            
        }

    }
}

Cmpts

Posted

Boas...

Quanto ao exemplo com o nome das tuas variáveis... Essa é muito simples!  😁  Acho que consegues lá chegar sozinho!  🙂 De qualquer maneira, neste exemplo, usei nomes como os teus.

O exemplo que aqui coloco também faz aquela coisinha de "ficar ao lado do relógio". Não sei se era bem isto que querias, mas com um bocado de pesquisa acho que consegues fazer o que queres.

Para que este exemplo funcione tens que fazer o seguinte:

[*]Arrasta um componente "NotifyIcon" (Na Toolbox, em Common Controls) para o teu Form.

[*]Tens que associar um ícone ao teu "NotifyIcon". Para isso tens que preencher a propriedade Icon do teu NotifyIcon com um ficheiro .ico válido (no meu teste usei este).

[*]Tens que criar um "handler" para evento Click do "NotifyIcon". O meu é representado pelo método notifyIcon1_Click.

[*]Tens que criar um "handler" para o evento Resize do teu formulário. O meu é representado pelo método Form1_Resize.

Tem atenção aos comentários do código e vai ficando atento ao fórum para o caso de alguém notar uma falha, ou sugerir uma implementação melhor!  🙂

using System;
using System.Windows.Forms;
using System.Threading;


namespace Tests
{
    public partial class Form1 : Form
    {
        private object lockObject = new object();
        private bool ficarEmLoop = true;
        private bool FicarEmLoop
        {
            get 
            {
                lock (lockObject)
                {
                    return ficarEmLoop;
                }
            }
            set 
            {
                lock (lockObject)
                {
                    ficarEmLoop = value;
                }
            }
        }


        /// <summary>
        /// Inicializa tudo.
        /// </summary>
        public Form1()
        {
            InitializeComponent();
            b_Stop.Enabled = false;
            lbl_Executando.Visible = false;
            lbl_Parado.Visible = true;
        }


        /// <summary>
        /// Handler do evento Click do Botão Stop (b_Stop)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void b_Stop_Click(object sender, EventArgs e)
        {
            FicarEmLoop = false;
            lbl_Executando.Visible = false;
            lbl_Parado.Visible = true;
            b_Stop.Enabled = false;
            b_Play.Enabled = true;            
        }


        /// <summary>
        /// Handler do evento Click do Botão Play (b_Play)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void b_Play_Click(object sender, EventArgs e)
        {
            FicarEmLoop = true; //Seta o Loop no programa
            lbl_Executando.Visible = true;
            lbl_Parado.Visible = false;
            b_Play.Enabled = false;
            b_Stop.Enabled = true;
                        
            // Dar ordem à ThreadPool para adicionar o método
            // ExecutaMeusComandos à sua "lista de execuções" 
            // (que ocorrerão numa outra thread).
            ThreadPool.QueueUserWorkItem(ExecutaMeusComandos);            
        }
        
        /// <summary>
        /// Irá executar os comandos do Loop.
        /// </summary>
        /// <param name="state"></param>
        private void ExecutaMeusComandos(object state)
        {
            while (FicarEmLoop)
            {
                //EXECUTA MEUS COMANDOS...                               
            }            
        }


        /// <summary>
        /// Handler do evento Resise do teu Form.
        /// Este evento é que fará com que o form "fique ao lado do relógio".
        /// Encontrei isto no Google com a seguinte pesquisa: c# minimize to tray
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_Resize(object sender, EventArgs e)
        {            
            if (this.WindowState == FormWindowState.Minimized)
            {
                // Quero que o meu icone "que fica no lado do relógio" fique visivel
                notifyIcon1.Visible = true;    
                // Texto e título para colocar no "balão" que aparece quando minimizamos para o tray
                notifyIcon1.BalloonTipText = "Para voltar a ver o formulário clique neste ícone.";
                notifyIcon1.BalloonTipTitle = "O meu programa";
                // Este balão fica visivel durante 1 segundo
                notifyIcon1.ShowBalloonTip(1000);
                
                // Quando minimizo não quero que o formulário apareça na minha barra de tarefas. 
                // Apenas o quero "ao lado do relógio"
                this.ShowInTaskbar = false;
                this.Hide();
            }            
        }


        /// <summary>
        /// Handler do evento Click do ícone do tray (o ícone "que fica no lado do relógio").
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void notifyIcon1_Click(object sender, EventArgs e)
        {
            // Quero que o meu formulário fique visivel.
            this.Show();
            // Quero que a minha janela volte ao estado "normal" -- pois ela tinha sido minimizada
            this.WindowState = FormWindowState.Normal;
            // Quero que o meu icone "que fica no lado do relógio" fique escondido
            this.notifyIcon1.Visible = false; 
        }


    }
}

Qq dúvida sobre interpretação do que eu disse, ou escrevi, não hesites.

Cmpts.

Posted

Vlw, a única coisa que não entendi foi esse bloco abaixo.

private bool FicarEmLoop

        {

            get

            {

                lock (lockObject)

                {

                    return ficarEmLoop;

                }

            }

            set

            {

                lock (lockObject)

                {

                    ficarEmLoop = value;

                }

            }

        }

Obrigado.

Posted

Boas...

É assim, nesta implementação simples, honestamente, isso é mais um preciosismo do que outra coisa. Isso tem a ver com conceitos programação concorrente e multi-thread. Esse lock garante-te acesso exclusivo à variável "ficarEmLoop": ou estás a ler, ou a escrever. Nunca acontecerá leitura e escrita ao mesmo tempo. Para leres mais sobre o assunto dá aqui um salto: http://www.inteligenciadigital.org/usando-lock-csharp-thread-dotnet/.

Honestamente, se isso te provoca confusão, podes retirar os locks, ou apagar mesmo a propriedade "FicarEmLoop" e usar apenas a "ficarEmLoop". Não estou a ver nenhuma forma deste código poder dar grandes problemas. Eu coloquei esses locks mais por ser uma boa prática proteger dados que são lidos ou escritos em duas Threads diferentes, ou seja, estou a proteger uma "secção crítica".

Cmpts.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...

Important Information

By using this site you accept our Terms of Use and Privacy Policy. We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.