2015-06-11 12 views
6

Niedawno musiałem wrócić do rozwiązywania problemów z kodem formularzy internetowych i napotkałem problem próbujący zaktualizować istniejącą stronę z listą odpowiedzi ankietowych.W jaki sposób otrzymujesz wartości z dynamicznych elementów sterujących w widoku listy na poczcie zwrotnej?

Mam ListView pokazujące szczegóły osób, które odpowiedziały na ankietę. Po kliknięciu ikony w wierszu ten wiersz wchodzi w tryb edycji i pokazuje jego informacje (imię, adres e-mail itp.) Jako pola wprowadzania.

Na razie dobrze, teraz muszę dodać pytania i odpowiedzi do tej ankiety i tej osoby. Pisanie ich jest łatwe, ale gdy oddzwoni się, wiersz wraca do ItemTemplate, a kontrola nie działa.

wiem z dynamicznymi kontroli Miałeś aby stworzyć w Page_Init tak webforms można je ponownie powiązać, ale tutaj kontrole nie są stworzone do imprezy ListItem ItemEditing, a dane zapisane w razie ItemUpdating.

Utknąłem na tym, jak mogę sterować we właściwym miejscu z odpowiednimi danymi we właściwym punkcie cyklu życia. Teraz próbuję pobrać wartości z Request.Form, ale z CheckboxList trudno jest ustalić, co zostało wybrane.

Edit: New przykład, że należy właściwie prowadzony

<%@ Page Language="C#" AutoEventWireup="true" CodeFile="QuestionExample.aspx.cs" Inherits="QuestionExample" %> 

<!DOCTYPE html> 

<html xmlns="http://www.w3.org/1999/xhtml"> 
<head runat="server"> 
    <title></title> 
</head> 
<body> 
    <form id="form1" runat="server"> 
       <table> 
     <asp:ListView runat="server" ID="LV" OnItemEditing="LV_OnItemEditing" OnItemUpdating="LV_OnItemUpdating"> 
      <LayoutTemplate> 
        <tr> 
         <td><asp:PlaceHolder runat="server" ID="itemPlaceHolder"></asp:PlaceHolder></td> 
        </tr>  
      </LayoutTemplate> 
      <ItemTemplate> 
       <asp:LinkButton ID="EditButton" runat="server" CommandName="Edit" Text="Edit"/> 
       ID: <asp:Label runat="server" ID="lblLeadID" Text="<%# ((Lead)Container.DataItem).LeadID %>" /> Name: <%# ((Lead)Container.DataItem).Name %><br/>     
      </ItemTemplate> 
      <EditItemTemplate> 
       <asp:LinkButton ID="UpdateButton" runat="server" CommandName="Update" Text="Update" /> 
       ID: <asp:Label runat="server" ID="lblLeadID" Text="<%# ((Lead)Container.DataItem).LeadID %>" /> <asp:Label runat="server">Name</asp:Label> 
       <asp:TextBox runat="server" id="tbName" Text="<%# ((Lead)Container.DataItem).Name %>"></asp:TextBox> 
       <asp:Panel runat="server" id="pnlQuestions"></asp:Panel> 
      </EditItemTemplate> 
     </asp:ListView> 
     </table> 
    </form> 
</body> 
</html> 

Następnie kod tyle:

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Web.UI; 
using System.Web.UI.WebControls; 

public partial class QuestionExample : Page 
{ 
    #region fake data 

    protected List<Question> Questions = new List<Question>() 
    { 
     new Question { QuestionID = 0, QuestionType = QuestionType.Textbox, QuestionText = "TextBox", Options = null }, 
     new Question { QuestionID = 1, QuestionType = QuestionType.DropDownList, QuestionText = "DDL", Options = new List<string> { "A", "B", "C"} }, 
    }; 

    protected List<Lead> Leads = new List<Lead> 
    { 
     new Lead { LeadID = 0, Name = "Bob", Answers = new Dictionary<string, string> { { "TextBox", "Hi" }, { "DDL", "B" } } }, 
     new Lead { LeadID = 1, Name = "Fred", Answers = new Dictionary<string, string> { { "TextBox", "Stuff" }, { "DDL", "C" } } }, 
    }; 

    #endregion  

    protected void Page_Load(object sender, EventArgs e) 
    { 
     LV.DataSource = Leads; 
     LV.DataBind(); 
    } 

    protected void LV_OnItemEditing(object sender, ListViewEditEventArgs e) 
    { 
     LV.EditIndex = e.NewEditIndex; 
     LV.DataBind(); 
     var leadLabel = (Label)LV.Items[e.NewEditIndex].FindControl("lblLeadID"); 
     var leadID = int.Parse(leadLabel.Text); 
     var panel = (Panel)LV.Items[e.NewEditIndex].FindControl("pnlQuestions"); 
     var lead = Leads.First(l => l.LeadID == leadID); 
     foreach (var answer in lead.Answers) 
     { 
      var question = Questions.First(q => q.QuestionText == answer.Key); 
      panel.Controls.Add(CreatQuestionControl(question, lead, true)); 
     } 
    } 

    protected Control CreatQuestionControl(Question question, Lead lead, bool setAnswers) 
    { 
     Control result = null; 
     switch (question.QuestionType) 
     { 
      case QuestionType.Textbox: 
       var tb = new TextBox(); 
       if (setAnswers) 
       { 
        var answer = lead.Answers[question.QuestionText]; 
        tb.Text = answer; 
       } 
       result = tb; 
       break; 
      case QuestionType.DropDownList: 
       var ddl = new DropDownList { DataSource = question.Options }; 
       ddl.DataBind(); 
       if (setAnswers) 
       { 
        var answer = lead.Answers[question.QuestionText]; 
        ddl.SelectedValue = answer; 
       } 
       result = ddl; 
       break; 
     } 

     return result; 
    } 

    protected void LV_OnItemUpdating(object sender, ListViewUpdateEventArgs e) 
    { 
     // Get input data here somehow 

     LV.EditIndex = -1; 
    } 
} 

public class Lead 
{ 
    public int LeadID { get; set; } 
    public string Name { get; set; } 
    public Dictionary<string, string> Answers { get; set; } 
} 

public class Question 
{ 
    public int QuestionID { get; set; } 
    public string QuestionText { get; set; } 
    public QuestionType QuestionType { get; set; } 
    public List<string> Options { get; set; } 
} 

public enum QuestionType 
{ 
    Textbox = 0, 
    DropDownList = 1, 
} 

Odpowiedz

6

Bez zobaczenia kodu trudno dać pełną odpowiedź, ale w zasadzie trzeba odtworzyć drzewo kontrolne, w tym formanty utworzone dynamicznie, na odświeżenie.

Możesz to zrobić, na przykład, w module obsługi zdarzeń Page_Load.

Możesz przechowywać wszystkie dane potrzebne do utworzenia drzewa kontrolnego w ViewState, aby było dostępne w PostBack.

Nie jestem pewien co masz na myśli przez:

... gdy postback dzieje wiersz sięga ItemTemplate

spodziewałbym EditIndex pozostać niezmienione po odświeżenie strony , chyba że jawnie go modyfikujesz, a zatem wiersz edycji pozostanie niezmieniony i użyjesz EditItemTemplate.

Jeśli możesz zamieścić uproszczoną próbkę, która ilustruje Twój problem, ja (lub ktoś inny) może być w stanie Ci pomóc.

UPDATE

Na podstawie zamieszczonych kodu, trzeba odtworzyć dynamiczne kontrole obsługi zdarzeń ItemUpdating i dodać je do drzewa kontroli w tej samej kolejności, jak stworzył je w obsługi zdarzeń ItemEditing. To znaczy. prawdopodobnie trzeba powtórzyć kod:

var questionPannel = lL.Items[e.ItemIndex].FindControl("lead_table") as HtmlTable; 
var campaignQuestionsTableRow = questionPannel.FindControl("campaign_questions") as HtmlTableRow; 

var questions = GetQuestions(); 

foreach(var question in questions) 
{ 
    // This builds a WebControl for the dynamic question 
    var control = CreateQuestionControl(question); 
    campaignQuestionsTableRow.AddControl(control); 
} 

UPDATE 2

Podczas aktualizacji, trzeba odtworzyć dynamiczne elementy sterujące na odświeżenie strony.Zmienić obsługi zdarzeń Page_Load do czegoś podobnego:

protected void Page_Load(object sender, EventArgs e) 
{ 
    LV.DataSource = Leads; 
    LV.DataBind(); 
    if (IsPostBack) 
    { 
     if (LV.EditIndex >= 0) 
     { 
      var leadLabel = (Label)LV.Items[LV.EditIndex].FindControl("lblLeadID"); 
      var leadID = int.Parse(leadLabel.Text); 
      var panel = (Panel)LV.Items[LV.EditIndex].FindControl("pnlQuestions"); 
      var lead = Leads.First(l => l.LeadID == leadID); 
      foreach (var answer in lead.Answers) 
      { 
       var question = Questions.First(q => q.QuestionText == answer.Key); 
       panel.Controls.Add(CreatQuestionControl(question, lead, true)); 
      } 

     } 
    } 
} 

Na pierwszym odświeżenie strony (kliknij Edit), EditIndex będzie -1, a dynamiczne elementy sterujące są tworzone w programie obsługi OnItemEditing.

Po drugim odświeżeniu zwrotnym (kliknij przycisk Aktualizuj), EditIndex będzie indeksem linii, którą edytujesz, i musisz odtworzyć dynamiczne formanty w Page_Load. Jeśli to zrobisz, znajdziesz wartości zaksięgowane, gdy dojdziesz do obsługi zdarzeń OnItemUpdating.

Chociaż uważam, że warto zrozumieć, jak używać dynamicznych elementów sterujących w ten sposób, w aplikacji produkcyjnej prawdopodobnie użyłbym wzmacniacza wewnątrz EditItemTemplate, jak sugeruje Elisheva Wasserman. Repeater może zawierać kontrolkę UserControl, która hermetyzuje logikę, aby ukryć/pokazać elementy interfejsu użytkownika w oparciu o typ pytania.

+0

OK, dodałem przykład. co mam na myśli, powracam do ItemTemplate powinno być nieco bardziej przejrzyste, pytania są wyświetlane tylko w EditItemTemplate, w którym je wypełniasz, jego zapisanie, a następnie strona pokazuje ItemTemplate bez tych kontrolek. – Mant101

+0

Próbowałem już tego, ale nie mają wartości w nich umieszczone. Z tego, co udało mi się znaleźć, muszę je utworzyć w Page_Load, aby dane mogły zostać ponownie powiązane, a uczynienie ich w iL_ItemUpdating jest zbyt późne w cyklu życia. – Mant101

+0

@ Mant101 - Page_Load byłoby lepszym miejscem do ich tworzenia. Być może mógłbyś sprawdzić 'IsPostBack && (EditIndex> = 0)' w Page_Load i odtworzyć tam kontrolki. Jeśli możesz podać minimalną kompletną próbkę, która demonstruje problem (http://stackoverflow.com/help/mcve) ja lub ktoś inny będzie w stanie Ci pomóc. – Joe

1

Powinieneś użyć wewnętrznego Repeatera lub listView, które będą wiązały zdarzenie item_edit, zamiast odtwarzać dynamikę kontroluje każdy post. ten sposób.

<asp:ListView ID="lL" runat="server" OnItemEditing="lL_ItemEditing"  OnItemUpdating="lL_ItemUpdating"> 
<itemtemplate> 
Read only view here... 
</itemtemplate> 
<edititemtemplate> 
<asp:LinkButton D="UpdateButton" runat="server" CommandName="Update" /> 
<table runat="server" ID="lead_table" class="lead_table"> 
    <tr id="Tr1" style="background-color:#EEEEEE;" runat="server" > 
     <td>Name: <asp:TextBox ID="Name" /></td> 
     Other Fixed controls... 
    </tr> 
    <tr runat="server" ID ="campaign_questions"> 
     <asp:Repeater id='repetur1' runat="server"> 
     <ItemTemplate> 
    <asp:Label id='lblCaption' runat='server" Text='<%Eval("QuestionTitle")%>' /> 

<asp:TextBox id='name' runat="server" /> 
</ItemTemplate> 
</asp:Repeater> 
    </tr> 
</table> 

na kodzie za

protected void lL_ItemEditing(object sender, ListViewEditEventArgs e) 
{    
var questionPannel = lL.Items[e.ItemIndex].FindControl("lead_table") as HtmlTable; 
var campaignQuestionsTableRow = questionPannel.FindControl("campaign_questions") as HtmlTableRow; 

// bind fixed controls 
var lead = GetLead(); 
var nameControl = ((TextBox)lL.Items[e.ItemIndex].FindControl("Name")) 
nameControl.Text = lead.Name; 

// bind dynamic controls 
var questions = GetQuestions(); 

    var rep= (Repeater)lL.Items[e.ItemIndex].FindControl("repeatur1"); 
rep.DataSource=questions; 
rep.DataBind(); 
} 

protected void lL_ItemUpdating(object sender, ListViewUpdateEventArgs e) 
{ 
    // Get fixed fields 
    // var lead = GetLead(); 
    lead.Name = ((TextBox)lL.Items[e.ItemIndex].FindControl("Name")).Text.Trim(); 
Repeater rep=(Repeater)e.FindControl("repeatur1")); 
    foreach (RepeaterItem item in rep.Items) 
{ 

TextBox t=item.FindControl("txtName") as TextBox; 
//do your work here 
    } 
// Switch out of edit mode 
lL.EditIndex = -1; 
} 
+0

Pytania mogą wyglądać zupełnie inaczej, jedna ankieta może mieć listę przycisków radiowych, jedno pole tekstowe i tak dalej. Sądzę więc, że wzmacniacz będzie potrzebował każdego typu pytania, a następnie ukrył te, które nie są używane do tego pytania? – Mant101

+0

Tak, chociaż wygląda na skomplikowaną, jest lepszą opcją, dynamiczne utworzone formanty nie są przechowywane w widoku i nie zawierają wielu błędów. możesz użyć Eval w znacznikach, aby zmienić widoczność niepotrzebnych elementów sterujących. Użyj właściwości serwera Widoczne, a nie propery klienta, więc asp.net w ogóle nie utworzy formantów hiddne. –

Powiązane problemy