我正在使用以下代码尝试Timer类: -
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();
}
最初,Label1.Text是" 1"。
但是当我运行该应用程序时,标签的文字显示为1并且不会增加。
答案 0 :(得分:2)
正如其他答案中已经提到的那样,System.Timers.Timer在非GUI线程上被触发。这不会允许您访问GUI元素并会引发跨线程异常。您可以使用MethodInvoker访问tm_Elapsed
事件中的GUI元素。由于您在表单中有Timer并且想要访问GUI元素,因此其他Timer类最适合您System.Windows.Forms.Timer。
实现以用户定义的间隔引发事件的计时器。 此计时器已针对Windows窗体应用程序进行了优化,并且必须 在窗口中使用。
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();
}
根据OP的评论编辑,他正在网页中执行此操作,而不是加载事件名称所示的表单。
如果您不需要任何服务器,可以使用javascript。如果您想更新html控件并需要从服务器执行,那么您可以使用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>
背后的代码
protected void UpdateTimer_Tick(object sender, EventArgs e)
{
Label1.Text = int.Parse(Label1.Text) + 1;
}
答案 1 :(得分:1)
试试这个:
void tm_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Label1.Invoke((Action)(() =>
{
int lbl = Convert.ToInt32(Label1.Text);
Label1.Text = (lbl+1).ToString();
}));
}
问题是System.Timers.Timer
在非UI线程中触发其事件,并且由于您无法从非UI线程安全地访问或更新控件,因此它似乎不起作用。
在UI元素上调用.Invoke(...)
允许您将代码推送到UI线程,使其安全。
答案 2 :(得分:1)
System.Timers.Timer旨在用于多线程环境。您不能直接访问Elapsed事件中的ui元素。
如果您的应用程序是Windows窗体,请使用System.Windows.Forms.Timer。 如果您的应用程序是WPF,请使用System.Windows.Threading.DispatcherTimer。
如果出于任何原因想要使用System.Timers.Timer,请使用ui元素的Invoke方法。例如,在Windows窗体中:
Label1.Invoke(new Action(() =>
{
int lbl = Convert.ToInt32(Label1.Text);
Label1.Text = (lbl+1).ToString();
}));
答案 3 :(得分:0)
您可以尝试以下,
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();
}
问题是,WPF / Windows Forms / Windows 8 app / WP 8(.1)应用程序不允许从不同的线程更改UI。您需要UI线程来更新它。
答案 4 :(得分:0)
尝试将System.Threading.Timer(线程安全)与@Enigmativity解决方案结合使用以避免跨线程异常:
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();
}));
}