2015-07-21 30 views
9

Spędziłem dwa dni z innym kolegą, badając to. Byłem zaskoczony, ponieważ większość rozwiązań omawiających ten problem ma albo złe rozwiązanie, albo rozwiązanie, które działa, jak sądzę, z niewłaściwych powodów.Zadzwoń do RaisePostBackEvent pod niewłaściwą kontrolą

Mamy niestandardowe sterowanie przyciskami, które musi podnieść zdarzenie ServerClick po jego naciśnięciu. Oto zestawione kod:

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(); 
    } 
} 

W przeglądarce zakończyć kod wykorzystuje dwa z tych przycisków

<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> 

Problem: Impreza nie jest podniesione na przycisk akceptacji. Debugowanie ujawnia, że ​​RaisePostBackEvent jest wywoływane, ale na przycisku Zamknij, który nie ma dołączonej obsługi ServerClick, więc nic się nie dzieje. Żadne procedury obsługi zdarzeń nie zostaną wywołane.

Uwagi:

  • Problemem nie jest widoczne, jeśli istnieje tylko jeden myButton na stronie.
  • Jeśli przyciski zostaną zmienione tak, że przycisk akceptacji jest ostatnim na stronie, zacznie działać.
  • Przeniesienie przycisków poza znacznikiem formularza powoduje, że zdarzenia działają zgodnie z oczekiwaniami, a obsługa zdarzeń przycisków akceptujących jest wywoływana poprawnie.
  • Implementacja IPostBackDataHandler i wywołanie RaisePostBackEvent() z IPostBackDataHandler::RaisePostDataChangedEvent() powoduje prawidłowe podniesienie zdarzenia na przycisku akceptacji, gdy znajduje się wewnątrz znacznika formularza.
  • Wywołanie RegisterRequiresRaiseEvent(btnAccept) podczas PageLoad tras zdarzeń prawidłowo do przycisku akceptowania.

Pytanie:

Jaki jest prawidłowe rozwiązanie od tych, które działają powyżej? Czy istnieje inne rozwiązanie? Potrzebujemy go do działania w taki sposób, aby wiele przycisków na stronie generowało zdarzenia niezależnego kliknięcia, bez względu na ich kolejność lub pozycję na stronie.

Moje myśli:

  • Ten problem wydaje się być omówione tutaj: http://forums.asp.net/t/1074998.aspx?ASP+NET+RaisePostbackEvent+Issues
  • Jeden to pozwalają przypuszczać, że nazywając __doPostback() z prawidłowym __EVENTTARGET powinien automatycznie trasa zdarzenie poprawnie przycisku, ale to się nie dzieje w rzeczywistości. Dzieje się tak tylko wtedy, gdy implementujemy również IPostBackDataHandler. Wiele rozwiązań w Internecie zdaje się wskazywać na to, że __doPostback, UniqueID itp. Jako winowajca, gdy faktycznie wdraża się IPostBackDataHandler, to wydaje się, że problem jest pozornie rozwiązany.
  • Sterownik implementuje IPostBackEventHandler, ale nie IPostBackDataHandler. Myślę, że to jest poprawne, ponieważ kontrola nie musi podnosić żadnych zdarzeń opartych na danych. Wdrożenie IPostBackDataHandler, aby działało, wydaje się być hackerem.
  • Korzystanie z RegisterRequiresRaiseEvent jest niezrozumiałe, a poza tym nie będzie działać, jeśli wiele przycisków na stronie chce podnieść zdarzenia.
  • Zastanawiam się, jak to robi asp:Button?
+0

klasa publiczna MyButton: Button – EJD

+0

@EJD, nie możemy zmienić hierarchii klas – Ali

Odpowiedz

0

Symulowałem sytuację. Mam nadzieję, że to pomaga. Istnieje klasa myButton WebServerControl:

[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(); 
    } 
} 

Potem użył mojego kontrolę serwera WWW w projekcie, powiedzmy, że jest to 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> 

A ja w default.aspx.cs Wcześniej realizowane po prostu zdarzenie: tylko

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

Lampa AcceptClickHandler po kliknięciu na przycisk Akceptuj i nie przycisk Zamknij.
Przepraszam, jeśli nie udało mi się prawidłowo rozwiązać problemu.

+0

Dzięki, możesz opisać dokładnie, co zmieniliście, co powoduje, że zdarzenia uruchamiają się poprawnie. Próbowałem komentować 'Name = string.Empty', ale to nie pomogło. Również oba przyciski muszą znajdować się wewnątrz znaczników '' '

', a nie na zewnątrz. – Ali

+0

Niestety, nie wkleiłem całego fragmentu kodu, przyciski znajdują się w znacznikach formularza. '

\t \t \t
' – tanuk