Jacrys
Jacrys

Reputation: 715

I have a C# Windows Forms Application and I want the user to be able to schedule a recurring task

My application sends out an email based on data from the entered form on the UI. The UI also allows them to "schedule" this as a job. I don't really want to use outside classes, e.g. Quartz. I also don't want to use the task scheduler as this would require completely rewriting my app... I understand that this can be done with timers, and I have attempted to use the Windows.Forms.Timer, however, I am not getting the desired results. I want it to run at the user specified interval and time, until the set end date.

private void Submit_Btn_Click(object sender, EventArgs e)
    {
        bool run = false;
        Location_Alert_Timer.Tick += new EventHandler(Location_Alert_Timer_Tick);

        if (Schedule_Chk.Checked == true)
        {
            run = true;

            if (Recur_Txt.Text != "" || Recur_Txt.Text != "0")
            {
                while (run == true)
                {

                    if ((Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy HH:mm")) <= Convert.ToDateTime(End_Date.Value.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text)))
                    {
                        //Execute_Command();
                        DateTime dt1;
                        DateTime dt2;
                        TimeSpan ts = new TimeSpan(Convert.ToInt16(Recur_Txt.Text),0,0,0);
                        //TimeSpan ts = new TimeSpan(0,0,30);
                        dt1 = Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy HH:mm"));
                        dt2 = Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text);
                        if  (dt1 >= dt2)
                        {
                            Execute_Command();
                            Location_Alert_Timer.Interval = (Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text + ":00.000").Add(ts) - DateTime.Now).Milliseconds;
                            Location_Alert_Timer.Start();
                            while (Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy HH:mm")) <= Convert.ToDateTime(End_Date.Value.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text))
                            {
                                Application.DoEvents();
                            }
                        }
                        else
                        {
                            Location_Alert_Timer.Interval = (Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text + ":00.000") - DateTime.Now).Milliseconds;
                            Location_Alert_Timer.Start();
                            while (exitFlag == false)
                            {
                                Application.DoEvents();
                            }
                        }
                    }
                    else
                    {
                        Location_Alert_Timer.Stop();
                        run = false;
                    }
                }
            }
            else
            {
                Execute_Command();
            }
        }
        else
        {
            Execute_Command();
        }
    }

    void Location_Alert_Timer_Tick(object sender, EventArgs e)
    {
        if (Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy HH:mm")) <= Convert.ToDateTime(End_Date.Value.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text))
        {
            Execute_Command();
        }
        else
        {
            exitFlag = true;
        }
    }

My timer events do not seem to be firing right and I know it is because I have set them up incorrectly...

Here is the form UI: Form UI

If anyone has a similar implementation in the future, @itsmatt's explanation led me to rewrite my whole event, from the ground up...below is the final implementation, and it works fantastically:

        private void Submit_Btn_Click(object sender, EventArgs e)
    {
        bool run = false;


        if (Schedule_Chk.Checked == true)
        {
            run = true;

            if (Recur_Txt.Text != "" || Recur_Txt.Text != "0")
            {
                while (run == true)
                {
                    if ((Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy HH:mm")) <= Convert.ToDateTime(End_Date.Value.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text)))
                    {
                        DateTime dt1;
                        DateTime dt2;
                        TimeSpan ts = new TimeSpan(Convert.ToInt16(Recur_Txt.Text),0,0,0);
                        dt1 = Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy HH:mm"));
                        dt2 = Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text);
                        if (dt1 >= dt2)
                        {
                            Execute_Command();
                            Location_Alert_Timer.Interval = Convert.ToInt32((Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text + ":00.000").Add(ts) - DateTime.Now).TotalMilliseconds);
                            Location_Alert_Timer.Start();
                            timerActive = true;
                            TimerHold();
                        }
                        else
                        {
                            Location_Alert_Timer.Interval = Convert.ToInt32((Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text + ":00.000") - DateTime.Now).TotalMilliseconds);
                            singleuse = true;
                            Location_Alert_Timer.Start();
                            timerActive = true;
                            TimerHold();
                            MessageBox.Show(DateTime.Now.ToString());
                            MessageBox.Show(DateTime.Now.Add(ts).ToString());
                            MessageBox.Show((Convert.ToDateTime(DateTime.Now.Add(ts).ToString()) - DateTime.Now).TotalMilliseconds.ToString());
                            Location_Alert_Timer.Interval = Convert.ToInt32((Convert.ToDateTime(DateTime.Now.Add(ts).ToString()) - DateTime.Now).TotalMilliseconds);
                            Location_Alert_Timer.Start();
                            timerActive = true;
                            TimerHold();
                        }
                    }
                    else
                    {
                        Location_Alert_Timer.Stop();
                        run = false;
                    }
                }
            }
        }
    }

    public void TimerHold()
    {
        while (timerActive)
        {
            Application.DoEvents();
        }
    }

    void Location_Alert_Timer_Tick(object sender, EventArgs e)
    {
        if (singleuse)
        {
            if (uses < 1)
            {
                if (Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy HH:mm")) <= Convert.ToDateTime(End_Date.Value.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text))
                {
                    uses++;
                    //DoItOnce();
                    Execute_Command();
                }
                else
                {
                    timerActive = false;
                }
            }
            else
            {
                singleuse = false;
                timerActive = false;
                Location_Alert_Timer.Stop();
            }
        }
        else
        {
            if (Convert.ToDateTime(DateTime.Now.ToString("MM/dd/yyyy HH:mm")) <= Convert.ToDateTime(End_Date.Value.ToString("MM/dd/yyyy") + " " + Recur_Time_Txt.Text))
            {
                //DoIt();
                Execute_Command();
            }
            else
            {
                timerActive = false;
            }
        }
    }

Upvotes: 1

Views: 366

Answers (2)

Jacrys
Jacrys

Reputation: 715

@kclewis Registering the tick event handler in the submit button click handler like you have will result in Location_Alert_Timer_Tick() being called once the first time the button is clicked, twice the next time, etc. It is registering the same callback function over and over, which results in multiple calls to that when the tick event is raised. Instead, += that event handler at init time (could be in the constructor or some other setup() function). That way you get one and only one function call to Location_Alert_Timer_Tick() when the timer tick event is raised. Posted via community wiki for @itsmatt

Upvotes: 0

what about using something like this example?

A-Simple-Scheduler-in-Csharp

Upvotes: 2

Related Questions