System.Timers.Timer doesn't work. [In asp.net web forms]

I am testing Timer class with this code: -

protected void Page_Load(object sender, EventArgs e)
{
    System.Timers.Timer tm = new System.Timers.Timer();
    tm.Elapsed += new System.Timers.ElapsedEventHandler(tm_Elapsed);
    tm.Interval = 1000;
    tm.Start();
}

void tm_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    int lbl = Convert.ToInt32(Label1.Text);
    Label1.Text = (lbl+1).ToString();
}

      

Initially Label1.Text is set to "1".

But when I run the application, the label text shows 1 and does not grow.

+3


source to share


5 answers


As mentioned in other answers, System.Timers.Timer runs on a non-GUI thread. This will prevent you from accessing the GUI element and will throw a cross-thread exception. You can use MethodInvoker to access the GUI element in the event tm_Elapsed

. Since you have a Timer in Forms and want to access the GUI element, another Timer class suits you best ie System.Windows.Forms.Timer .

Implements a timer that raises an event at user-defined intervals. This timer is optimized for use in Windows Forms applications and will need to be used in a window.

protected void Page_Load(object sender, EventArgs e)
{         
     System.Windows.Forms.Timer tm = new System.Windows.Forms.Timer();
     tm.Tick += tm_Tick;
     tm.Interval = 1000;
     tm.Start();
}

void tm_Tick(object sender, EventArgs e)
{
     int lbl = Convert.ToInt32(label1.Text);
     label1.Text = (lbl + 1).ToString();
}

      

Edit based on OP's comments that he does this on the webpage and not on winning forms as the title of the load event suggests.

You can use javascript if you don't need anything from the server. If you want to update the html control and need to do it from the server, you can use asp: Timer



Html (.aspx)

  <form id="form1" runat="server">             
        <asp:ScriptManager ID="ScriptManager1" runat="server" />
        <asp:Timer runat="server" id="UpdateTimer" interval="5000" ontick="UpdateTimer_Tick" />
        <asp:UpdatePanel runat="server" id="TimedPanel" updatemode="Conditional">
            <Triggers>
                <asp:AsyncPostBackTrigger controlid="UpdateTimer" eventname="Tick" />
            </Triggers>
            <ContentTemplate>
                 <asp:Label id="Label1" runat="server" Text="1" />
            </ContentTemplate>
        </asp:UpdatePanel>
    </form>

      

Code for

protected void UpdateTimer_Tick(object sender, EventArgs e)
{
    Label1.Text = int.Parse(Label1.Text) + 1;
}

      

+2


source


Try the following:

    void tm_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
    {
        Label1.Invoke((Action)(() =>
        {
            int lbl = Convert.ToInt32(Label1.Text);
            Label1.Text = (lbl+1).ToString();
        }));
    }

      



The problem is that it System.Timers.Timer

fires its event on a non-UI thread, and since you cannot safely access or update controls from a non-UI thread, it doesn't work.

Calling .Invoke(...)

on a UI element allows you to push code to the UI thread, which makes it safe.

+1


source


System.Timers.Timer is intended for use in a multi-threaded environment. You are not allowed to directly access ui elements inside the Elapsed event.

If your application is Windows Forms use System.Windows.Forms.Timer. If your application is WPF use System.Windows.Threading.DispatcherTimer.

If for any reason you want to use System.Timers.Timer use the Invoke method on your ui elements. For example, in Windows Forms:

Label1.Invoke(new Action(() =>
{
    int lbl = Convert.ToInt32(Label1.Text);
    Label1.Text = (lbl+1).ToString();
}));

      

+1


source


You can try the following,

if(this.Label1.InvokeRequired)
     {
         this.Label1.BeginInVoke((MethodInvoker) delegate() { int lbl = Convert.ToInt32(Label1.Text);
Label1.Text = (lbl+1).ToString();});    
     }
     else
     {
         int lbl = Convert.ToInt32(Label1.Text);
         Label1.Text = (lbl+1).ToString();
     }

      

The problem is that WPF / Windows Forms / Windows 8 app / WP 8 (.1) doesn't allow changing UI from different threads. The update requires a UI thread.

0


source


Try using System.Threading.Timer (Thread safe) combined with @Enigmativity's solution to throw a Cross-thread exception:

    private System.Threading.Timer m_timer = null;
    private const int DUE_TIME = 1000;
    private const int INTERVAL = 1000;

    private void Page_Load(object sender, EventArgs e)
    {
        System.Threading.AutoResetEvent autoEvent = new System.Threading.AutoResetEvent(false);
        System.Threading.TimerCallback tcb = new System.Threading.TimerCallback(timer_Elapsed);
        m_timer = new System.Threading.Timer(tcb, null, DUE_TIME, INTERVAL);
    }

    void timer_Elapsed(object sender)
    {
        label1.Invoke((Action)(() =>
        {
            int lbl = Convert.ToInt32(label1.Text);
            label1.Text = (lbl + 1).ToString();
        }));
    }

      

0


source







All Articles