下面的代码包含两个更新面板,两者都将UpdateMode
设置为“Conditional”。一个有Timer
触发每5秒,另一个有Label
和TextBox
(AutoPostBack
设置为true),有一个更改标签文本的有线TextChanged事件。计时器不参与页面呈现:它执行心跳和其他日志记录操作。每当用户在文本框中键入输入并且定时器触发时,会触发TextChanged事件,即使回发源自另一个更新面板(带有计时器的更新),也会有效地更改标签文本。我希望只有当文本框由于用户操作而松散焦点时才会触发TextChanged事件。可能吗?或者我应该避免使用System.Web.UI.Timer
并使用其他东西?在这种情况下是什么?
<%@ Page Title="Home Page" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="WebApplication1._Default" %>
<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
<asp:ScriptManager ID="ScriptManager1" runat="server"
EnablePartialRendering="true">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server"
ChildrenAsTriggers="False" UpdateMode="Conditional">
<ContentTemplate>
<asp:Timer ID="Timer1" runat="server" ontick="Timer1_Tick"
Interval="5000"></asp:Timer>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="Timer1" EventName="Tick" />
</Triggers>
</asp:UpdatePanel>
<asp:UpdatePanel ID="UpdatePanel2" runat="server"
ChildrenAsTriggers="False" UpdateMode="Conditional">
<ContentTemplate>
<asp:TextBox ID="TextBox1" runat="server" AutoPostBack="True"
ontextchanged="TextBox1_TextChanged"></asp:TextBox>
<asp:Label ID="Label1" runat="server"
Text="Label"></asp:Label>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="TextBox1"
EventName="TextChanged" />
</Triggers>
</asp:UpdatePanel>
</asp:Content>
代码背后:
protected void Timer1_Tick(object sender, EventArgs e)
{
// Heartbeat, logging and other stuff
}
protected void TextBox1_TextChanged(object sender, EventArgs e)
{
Label1.Text = TextBox1.Text;
}
我最终明白回发不太适合与页面渲染无关的后台活动。更简洁的方法是调用WebService或发布到不同的页面。扩展Timer
类,我能够实现第二个策略覆盖当计时器滴答时调用的javascript函数,使其能够执行Post到不同的url。请随意指出其他类似行为的ajax控件。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.ComponentModel;
using System.Text;
namespace AjaxExt
{
[ToolboxData("<{0}:TimerEx runat=server></{0}:TimerEx>")]
public class TimerEx : Timer
{
public const string POST_FIELD = "__TIMEREXDATA";
public TimerEx()
{
TimerMode = TimerMode.DoPostBack;
PostUrl = "";
PostData = "";
PostField = "";
}
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
if (TimerMode.HasFlag(TimerMode.DoPost) && !String.IsNullOrEmpty(PostUrl))
{
string postUrl = PostUrl.StartsWith("/") ? PostUrl : "/" + PostUrl;
string postField = String.IsNullOrEmpty(PostField) ? POST_FIELD : PostField;
// Override tick function
StringBuilder builder = new StringBuilder();
builder.AppendLine("function pageLoad() {");
builder.AppendLine(" var timer = $find('" + this.ClientID + "');");
builder.AppendLine(" timer._doPostback = function () {");
builder.AppendLine(" $.ajax({");
builder.AppendLine(" url: \"" + postUrl + "\",");
if (String.IsNullOrEmpty(PostData))
builder.AppendLine(" data: null,");
else
builder.AppendLine(" data: { " + postField + ": " + PostData + "},");
builder.AppendLine(" success: null,");
builder.AppendLine(" error: null");
builder.AppendLine(" });");
if (TimerMode.HasFlag(TimerMode.DoPostBack))
builder.AppendLine(" __doPostBack(this.get_uniqueID(),'');");
builder.AppendLine(" };");
builder.AppendLine("}");
Page.ClientScript.RegisterClientScriptBlock(typeof(Page), "dopostscript", builder.ToString(), true);
}
}
[DefaultValue(TimerMode.DoPostBack)]
public TimerMode TimerMode
{
get;
set;
}
[DefaultValue("")]
public string PostUrl
{
get;
set;
}
[DefaultValue("")]
public string PostData
{
get;
set;
}
[DefaultValue("")]
public string PostField
{
get;
set;
}
}
[Flags]
public enum TimerMode
{
DoPost = 1,
DoPostBack = 2,
DoBoth = DoPost | DoPostBack
}
}
它可以添加到页面中,如下所示:
<%@ Register Assembly="AjaxExt" Namespace="AjaxExt" TagPrefix="jaxext" %>
<ajaxext:TimerEx ID="PingTimer" runat="server" PostUrl="HeartBeat.aspx"
TimerMode="DoPost" Interval="10000" />