【问题标题】:Is it possible to specify the event to fire?是否可以指定要触发的事件?
【发布时间】:2015-09-29 07:33:08
【问题描述】:

可以在here 找到关于回发机制如何工作的非常详细的说明。

在 ASP.NET 中,控件通常有很多事件。例如LinkButton 类有Click 事件。

以下代码:

<asp:LinkButton ID="LinkButton1" runat="server" OnClick="LinkButton1_Click" Text="LinkButton" />

在客户端被翻译成这个:

<a id="LinkButton1" href="javascript:__doPostBack('LinkButton1','')">LinkButton</a>

如您所见,客户端的代码没有指定要触发的事件或事件处理程序。

所以我的问题是,如果服务器从客户端接收的唯一信息是组件的 ID(__doPostBack 方法的第一个参数),那么服务器如何知道它应该触发 Click 事件和 LinkButton1_Click 事件处理程序?

如果我希望组件触发与Click 不同的事件怎么办?

【问题讨论】:

  • 你想触发什么事件?在所描述的场景中,只有点击才有意义,这就是服务器知道的方式。
  • 正如@zespri 所说,没有其他事件可以挂钩。链接按钮也有一个命令事件,但是当它被点击时,点击和命令事件都会在服务器端触发。
  • 在这种情况下,是的,但是如果我有一个自定义控件,对于客户端来说,超过 1 个事件是有意义的,我将如何做到这一点?然后我应该在调用 doPostBack 时传递有关在 eventargs 中触发哪个事件的信息吗?
  • 您可以为此使用第二个参数“事件参数”。

标签: javascript asp.net events webforms


【解决方案1】:

ASP.NET Web 窗体始终创建一个包含页面中所有控件的窗体。每当用户单击页面中触发服务器中的事件的控件时,幕后发生的事情是表单正在发布到服务器。发帖不是简单的 POST,而是由客户端 __doPostback 函数完成,它接收两个参数:eventTargeteventArgument。第一个具有触发回发的控件的 ID,第二个包含任何额外信息。这些参数的值被复制到表单中的两个隐藏字段中,与表单的其余控件一起发布

一旦进入服务器,就可以读取此控件中的值以确定引发哪个事件。它们可以通过访问Request["__EVENTTARGET"];Request["__EVENTARGUMENT"];来读取

您可以阅读此 SO Q&A 和链接页面以了解更多信息:How to use __doPostBack()

ASP.NET 框架通过检查这些值并查找 ID 与 __EVENTTARGET 匹配的控件并实现 IPostBackEventHandler 来简化工作。要了解更多信息,请阅读:Server Event Handling in ASP.NET Web Forms Pagess

除了回发事件,还有“更改事件”。通过比较控件的原始值、发送到浏览器时的值和该控件中发布的值来引发此事件。例如,TextBox 具有 TextChanged 事件。为了确定事件是否必须触发,服务器从视图状态中提取控件的原始值(发送到浏览器的隐藏字段,带有所有重新处理的控件的状态,包括它们的值)并将其与发布的值,必要时触发事件。与IPostBackEventHandler 类似,实现IPostBackDataHandler 将允许框架查找需要处理此类事件的控件。

您还应该了解页面生命周期以了解服务器中发生的情况以及顺序:When to wire up event handlers asp.net

【讨论】:

  • 感谢您对整个机制的全面了解!实际上,我在问一个自定义控件是否可以在客户端引发多个事件。客户端代码仅发送触发事件的控件的标识符,而不指定发生了什么事件(因为可能对于所有标准控件,客户端只能在其浏览器中触发 1 个事件)。例如,按钮上的事件可能是点击它,或者将鼠标光标放在它上面。我能想到的唯一方法是发送有关在 __EVENTARGUMENT 中发生的事件的信息。
  • 是的,佳沛的回答解释了标准的做法。它与IpostBackEventHandler 实现有关:方法RaisePostBackEvent 由框架调用,因为事件目标匹配此控件。并且事件参数ClackeventArgument 中传递给此方法。有很多服务器控件有几个不同的事件。网格或网格内的控件就是很好的例子。我知道我的回答过于广泛,但如果您有时间阅读它,您将对 ASP.NET Web 窗体的工作原理有更清晰的认识。
【解决方案2】:

我要给出的例子对于任何实际目的都是无用的,但是你没有表明你的任何实际目的,所以我认为这是一个公平的游戏。我希望它将向您展示该方法,然后您将能够根据您的需要对其进行修改和扩展。

public class LinkButtonWithClack : LinkButton
{
    private const string ClackMarker = "Clack";
    public bool ClackMode { get; set; }
    protected override PostBackOptions GetPostBackOptions()
    {
        var options = base.GetPostBackOptions();
        if (ClackMode)
        {
            // That's how you specify the event argument for __EVENTARGUMENT
            options.Argument = ClackMarker;
        }
        return options;
    }

    public event EventHandler Clack;

    protected override void RaisePostBackEvent(string eventArgument)
    {
        if (eventArgument == ClackMarker)
        {
            this.OnClack(EventArgs.Empty);
        }
        else
        {
            base.RaisePostBackEvent(eventArgument);
        }          
    }

    protected virtual void OnClack(EventArgs e)
    {
        if (Clack != null)
        {
            Clack(this, e);
        }
    }
}

在本例中,您将创建一个新的服务器控件LinkButtonWithClack。此控件继承自LinkButton 服务器控件,并具有一个附加事件Clack。如果将属性 ClackMode 设置为 true,它将开始生成 Clacks 而不是 Clicks。

通过第二个参数向doPostBack 传达点击或咔哒声是否和事件:

<a id="MainContent_LinkButtonWithClack1" 
href="javascript:__doPostBack(&#39;ctl00$MainContent$LinkButtonWithClack1&#39;,&#39;Clack&#39;)">

服务器然后检查它的内容,如果看到“Clack”,则调用Clack 事件。

当然,您不太可能从LinkButton 派生,我只是将其用作示例,因为您这样做了。您可能会从头开始实施服务器控件。这样做时,请带上您在服务器控件创建方面的所有知识,或者如果您没有,请阅读 - 您将需要它。

顺便说一句,今天使用 asp.net mvc 比使用 webforms 更容易找到帮助,因为后者更老,使用它的人越来越少。如果您对技术选择有任何发言权,我几乎会选择 asp.net mvc 而不是 webforms。

【讨论】:

    猜你喜欢
    • 2016-01-14
    • 2012-11-08
    • 1970-01-01
    • 2015-11-02
    • 1970-01-01
    • 2011-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多