2015-07-21 7 views
9

Ich habe zwei Tage mit einem anderen Kollegen verbracht, der das untersucht hat. Ich war überrascht, dass die meisten Lösungen, die dieses Problem diskutieren, entweder die falsche Lösung oder eine Lösung haben, die aus den falschen Gründen funktioniert.RaisePostBackEvent bei falscher Kontrolle aufgerufen

Wir haben ein benutzerdefiniertes Schaltflächensteuerelement, das ein ServerClick-Ereignis auslösen muss, wenn es gedrückt wird. Hier ist der zusammengefasste Code:

public class MyButton : WebControl, IPostBackEventHandler 
{ 
    protected HtmlGenericControl _Button; 
    protected string _OnClick = ""; 
    protected string _Name; 
    public event EventHandler ServerClick; 
    // etc...  

    public MyButton() 
    { 
     Width = Unit.Pixel(100); 
     _Button = new HtmlGenericControl("button"); 
     Controls.Add(_Button); 
    } 

    protected override void Render(HtmlTextWriter writer) 
    { 
     _Button.Attributes.Add("id", string.IsNullOrEmpty(_Name) ? base.ID : _Name); 
     _Button.Attributes.Add("name", _Name); 

     // etc... 

     _OnClick = Page.ClientScript.GetPostBackEventReference(this, ""); 
     _Button.Attributes.Add("onClick", _OnClick); 

     // etc... 

     ID = String.Empty; 
     Name = String.Empty; 
     AccessKey = String.Empty; 
     TabIndex = -1; 
     Width = Unit.Empty; 

     base.Render(writer); 
    } 

    protected virtual void OnServerClick() 
    { 
     if (this.ServerClick != null) 
     { 
      this.ServerClick(this, new EventArgs()); 
     } 
    } 

    public void RaisePostBackEvent(string eventArgument) 
    { 
     this.OnServerClick(); 
    } 
} 

Auf dem Browser den Code Endverwendungen zwei diese Tasten

<form> 

    <!-- etc ... --> 

    <div class="row actionBar"> 
     <PGSC:MyButton Name="btnAccept" ID="btnAccept" LabelID="3244" TabIndex="70" runat="server" OnServerClick="AcceptClickHandler"/> 
     <PGSC:MyButton Name="btnClose" ID="btnClose" LabelID="349" OnClick="window.returnValue=frmMMD.hdnMmdId.value;window.close();" TabIndex="80" runat="server" /> 
    </div> 
</form> 

Das Problem: Die Veranstaltung nicht auf der akzeptieren Taste ausgelöst wird. Debugging zeigt, dass RaisePostBackEvent aufgerufen wird, aber auf die Schließen-Schaltfläche, die keinen ServerClick Handler angeschlossen hat, daher passiert nichts. Es werden keine Ereignishandler aufgerufen.

Hinweise:

  • Das Problem gesehen wird, nicht, wenn es nur eine MyButton auf der Seite.
  • Wenn die Schaltflächen so angeordnet sind, dass die Schaltfläche "Akzeptieren" die letzte auf der Seite ist, beginnt sie zu arbeiten.
  • Wenn Sie die Schaltflächen außerhalb des Formular-Tags bewegen, werden die Ereignisse wie erwartet ausgeführt, und der Event-Handler für die Accept-Schaltflächen wird korrekt aufgerufen.
  • Das Implementieren von IPostBackDataHandler und das Aufrufen von RaisePostBackEvent() von IPostBackDataHandler::RaisePostDataChangedEvent() bewirkt, dass das Ereignis auf der Schaltfläche "Annehmen" innerhalb des Formular-Tags korrekt ausgelöst wird.
  • Der Aufruf von RegisterRequiresRaiseEvent(btnAccept) während PageLoad leitet Ereignisse korrekt an die Schaltfläche "Annehmen" weiter.

Die Frage:

Was ist die richtige Lösung von denen, die oben arbeiten? Oder gibt es eine andere Lösung? Es muss so funktionieren, dass mehrere Schaltflächen auf der Seite unabhängig von ihrer Reihenfolge oder Position auf der Seite unabhängige Klickereignisse auslösen können.

Meine Gedanken:

  • Dieses Problem hier diskutiert zu werden scheint: http://forums.asp.net/t/1074998.aspx?ASP+NET+RaisePostbackEvent+Issues
  • Eine Leitung ist zu glauben, dass Aufruf __doPostback() mit den richtigen __EVENTTARGET sollte automatisch Route das Ereignis korrekt auf die Taste, aber Das passiert in Wirklichkeit nicht. Es passiert nur, wenn wir auch IPostBackDataHandler implementieren. Viele Lösungen auf dem Web scheinen auf __doPostback, UniqueID usw. als der Übeltäter zu zeigen, wenn die tatsächliche Implementierung IPostBackDataHandler ist, was scheinbar das Problem behebt.
  • Die Steuerung implementiert IPostBackEventHandler, aber nicht IPostBackDataHandler. Ich denke, das ist richtig, da das Steuerelement keine datengesteuerten Ereignisse auslösen muss. Die Implementierung von IPostBackDataHandler, damit es funktioniert, scheint wie ein Hack zu sein.
  • Die Verwendung von RegisterRequiresRaiseEvent ist nicht intuitiv und wird außerdem nicht funktionieren, wenn mehrere Schaltflächen auf der Seite Ereignisse auslösen möchten.
  • Ich frage mich, wie macht ein es?
+0

öffentliche Klasse MyButton: Schaltfläche – EJD

+0

@EJD, wir sind nicht berechtigt, die Klassenhierarchie zu ändern – Ali

Antwort

0

Ich habe eine Situation simuliert. Hoffe es hilft. Es gibt die MyButton WebServerControl Klasse:

[DefaultProperty("Text")] 
[ToolboxData("<{0}:MyButton runat=server></{0}:MyButton>")] 
public class MyButton : WebControl, IPostBackEventHandler 
{ 
    [Bindable(true)] 
    [Category("Appearance")] 
    [DefaultValue("")] 
    [Localizable(true)] 
    public string Text 
    { 
     get 
     { 
      String s = (String)ViewState["Text"]; 
      return ((s == null) ? String.Empty : s); 
     } 

     set 
     { 
      ViewState["Text"] = value; 
     } 
    } 

    protected HtmlGenericControl _Button; 
    protected string _OnClick = ""; 
    protected string _Name; 
    public event EventHandler ServerClick; 
    // etc...  

    public MyButton() 
    { 
     Width = Unit.Pixel(100); 
     _Button = new HtmlGenericControl("button"); 
     Controls.Add(_Button); 
    } 

    protected override void Render(HtmlTextWriter writer) 
    { 
     _Button.Attributes.Add("id", string.IsNullOrEmpty(_Name) ? base.ID : _Name); 
     _Button.Attributes.Add("name", _Name); 

     // etc... 

     _OnClick = Page.ClientScript.GetPostBackEventReference(this, ""); 
     _Button.Attributes.Add("onClick", _OnClick); 

     // etc... 

     ID = String.Empty; 
     //Name = String.Empty; 
     AccessKey = String.Empty; 
     TabIndex = -1; 
     Width = Unit.Empty; 

     base.Render(writer); 
    } 

    protected virtual void OnServerClick() 
    { 
     if (this.ServerClick != null) 
     { 
      this.ServerClick(this, new EventArgs()); 
     } 
    } 

    public void RaisePostBackEvent(string eventArgument) 
    { 
     this.OnServerClick(); 
    } 
} 

ich dann in einem Projekt meiner Web-Server-Steuerelement verwendet wird, sagen wir mal so ist die default.aspx:

<div><cc1:MyButton ID="btnAccept" runat="server" TabIndex="70" OnServerClick="AcceptClickHandler" /> 
<cc1:MyButton ID="btnClose" Text="Close" Width="256px" LabelID="349" runat="server" TabIndex="80" /></div><div> 
    <asp:Label ID="Label1" runat="server" Text="Label"></asp:Label> 
</div> 

Und in default.aspx.cs I habe einfach das Ereignis implementiert:

protected void AcceptClickHandler(object sender, EventArgs e) 
    { 
     Label1.Text = DateTime.Now.ToLongTimeString(); 
    } 

die AcceptClickHandler Feuer nur, wenn Sie auf die Schaltfläche Akzeptieren und nicht auf die Schaltfläche Schließen klicken.
Sorry, wenn ich nicht das Problem richtig verstanden habe.

+0

Danke, können Sie genau beschreiben, was Sie geändert haben, dass die Ereignisse ordnungsgemäß ausgelöst werden. Ich habe versucht, "Name = String.Empty" auskommentieren, aber das hat nicht geholfen. Auch müssen sich beide Tasten innerhalb der '' Tags befinden, nicht außerhalb. – Ali

+0

Entschuldigung, ich habe nicht den ganzen Code eingefügt, die Buttons sind in den Form-Tags. '

\t \t \t
' – tanuk

Verwandte Themen