nspyrou Δημοσ. 15 Ιουνίου 2011 Δημοσ. 15 Ιουνίου 2011 Κύριοι συνάδελφοι, καλησπέρα σας, Έχω ένα πρόβλημα με μια φόρμα φτιαγμένη σε ASP.NET 4.0 (.NET Framework 4.0 that is,). Μέσα από μια δομή που έχω δημιουργήσει στη βάση δεδομένων, διαβάζω κατηγορίες ειδών και είδη καταλόγου, (μενού καταστήματος), και δημιουργώ στην αντίστοιχη σελίδα, πίνακα που περιέχει το είδος, ένα asp:CheckBox και ένα asp:TextBox για την επιλογή του είδους και την δήλωση της ποσότητας παραγγελίας. Η σελίδα κάνει inherit από την Master σελίδα που έχω φτιάξει. Πράγμα που σημαίνει οτι υπάρχουν αντίστοιχα PlaceHolders για το content του Head και του Body. Kι εδώ έρχεται το πρόβλημα: Όταν πατήσω το κουμπί παραγγελία, (ένα <asp:Button>) θα περίμενε κανείς να μπορεί να κάνει loop μέσα στην form μέσω code behind, (foreach πχ), και να διαβάσει τις τιμές των server controls (checkbox & textbox) που υπάρχουν πάνω στη φορμα με τις αντίστοιχες τιμές τους. Μάταια όμως ... Πως μπορώ να κάνω submit τη φόρμa έτσι ώστε να μπορώ να κάνω iterate τα controls της φόρμας? (Υπενθυμίζω οτι δεν ξέρω ούτε πόσα είναι, ούτε ποιά είναι επιλεγμένα) Ευχαριστώ εκ των προτέρων!
_tasos Δημοσ. 15 Ιουνίου 2011 Δημοσ. 15 Ιουνίου 2011 Καλησπέρα, Τα controls της φόρμας πως τα περνάς δυναμικά; Φαντάζομαι τα κάνεις Add σε κάποιο PlaceHolder, σωστά; Τότε αν κάνεις for each με το collection myPlaceHolder.Controls θα έχεις όλα τα controls που έχεις εισάγει δυναμικά. Σε κάθε control, page, master page υπάρχει το collection this.Controls (ή Me.Controls αν παίζεις με VB). Το Me.Controls περιέχει όλα τα server controls του control που βρίσκεσαι. Αν π.χ. το τρέχεις στο control order_form.ascx θα σου φέρει όλα τα controls αυτού του user control. Αν πάλι είσαι σε μία σελίδα myorder.aspx θα σου φέρει τα controls που έχει η myorder.aspx. Αν η myorder.aspx περιέχει το order_form.ascx η Me.Controls θα περιέχει το ίδιο το order_form.ascx και όχι τα server controls που αυτό περιέχει. Τέλος, κάποια controls όπως η HtmlForm, ο PlaceHolder, κτλ λειτουργούν σαν containers και έχουν και αυτοί τη δική τους collection με controls. Και αυτά, δεν περιέχονται στο Me.Controls collection του control που έχει την HtmlForm. Ελπίζω να σε βοήθησα να καταλάβεις τι παίζει. Αν θέλεις κάνε post λίγο κώδικα, κάποιο απλό sample ίσως, για να δούμε πως είναι στημένη η φόρμα σου.
nspyrou Δημοσ. 16 Ιουνίου 2011 Μέλος Δημοσ. 16 Ιουνίου 2011 Καλησπέρα, Τα controls της φόρμας πως τα περνάς δυναμικά; Φαντάζομαι τα κάνεις Add σε κάποιο PlaceHolder, σωστά; Τότε αν κάνεις for each με το collection myPlaceHolder.Controls θα έχεις όλα τα controls που έχεις εισάγει δυναμικά. Σε κάθε control, page, master page υπάρχει το collection this.Controls (ή Me.Controls αν παίζεις με VB). Το Me.Controls περιέχει όλα τα server controls του control που βρίσκεσαι. Αν π.χ. το τρέχεις στο control order_form.ascx θα σου φέρει όλα τα controls αυτού του user control. Αν πάλι είσαι σε μία σελίδα myorder.aspx θα σου φέρει τα controls που έχει η myorder.aspx. Αν η myorder.aspx περιέχει το order_form.ascx η Me.Controls θα περιέχει το ίδιο το order_form.ascx και όχι τα server controls που αυτό περιέχει. Τέλος, κάποια controls όπως η HtmlForm, ο PlaceHolder, κτλ λειτουργούν σαν containers και έχουν και αυτοί τη δική τους collection με controls. Και αυτά, δεν περιέχονται στο Me.Controls collection του control που έχει την HtmlForm. Ελπίζω να σε βοήθησα να καταλάβεις τι παίζει. Αν θέλεις κάνε post λίγο κώδικα, κάποιο απλό sample ίσως, για να δούμε πως είναι στημένη η φόρμα σου. Φίλε _tasos σε ευχαριστώ πολύ για τη λεπτομερή περιγραφή σου. Όντως, τα controls τα εισάγω σε PlaceHolder όπως, σωστά, υποθέτεις. Δεν παίζω με User Controls, αλλά με δυναμικά server controls, που δημιουργούνται κατά το δοκούν, και ανάλογα με τις ανάγκες παρουσίασης του καταλόγου (Menu/Menu Items [αφου μιλάμε για μαγαζί]). Δυστυχώς το iteration στο collection PlaceHolder1.Controls αν και μου γυρνάει τα controls, δεν μου γυρνάει τις τιμές των controls. Πχ,αν το CheckBox είναι Checked μου επιστρέφει ως non checked. Όπως και τα TextBox ως κενά. Επίσης δοκίμασα να παίξω με το Page.Controls αλλά και πάλι το ίδιο αποτέλεσμα (δεν δοκίμασα το this.Controls αλλά νομίζω οτι είναι ίδιο με το Page.Controls, θα το δω αυτό!). Αν η φόρμα είναι προσχεδιασμένη (έχω ρίξει τα controls στο page.aspx σε design mode πχ), όλα είναι μια χαρά! Αν τα controls δημιουργούνται On-the-fly τζίφος! Έτσι φτιάχνω τη φόρμα και λειτουργεί άψογα! ... (Είναι σε C#) ... > string sQuery = "Select BLAH BLAH BLAH From Κλπ ...."; SqlDataAdapter da = new SqlDataAdapter(sQuery, cnConnection); DataTable dt = new DataTable(); da.Fill(dt); if (dt.Rows.Count > 0) { string Category = ""; Table Catalog = new Table(); Catalog.BorderWidth = 0; Catalog.CellSpacing = 0; Catalog.CellPadding = 2; PlaceHolder1.Controls.Add(Catalog); for (int i = 0; i < dt.Rows.Count; i++) { TableRow row = new TableRow(); if (Category.Length == 0 || Category != dt.Rows[i]["CategoryCode"].ToString()) { Category = dt.Rows[i]["CategoryCode"].ToString(); TableCell tc = new TableCell(); tc.Font.Bold = true; tc.Text = dt.Rows[i]["CategoryDescription"].ToString(); row.BackColor = System.Drawing.Color.LightGray; row.Cells.Add(tc); for (int j = 1; j <= 4; j++) { tc = new TableCell(); tc.Text = ""; row.Cells.Add(tc); } Catalog.Rows.Add(row); row = new TableRow(); } TableCell cell = new TableCell(); cell.Text = i.ToString(); row.Cells.Add(cell); cell = new TableCell(); cell.HorizontalAlign = HorizontalAlign.Left; cell.Text = dt.Rows[i]["GRDescription"].ToString(); row.Cells.Add(cell); cell = new TableCell(); [b] CheckBox chk = new CheckBox(); chk.ID = "chk_" + dt.Rows[i]["ItemId"].ToString(); cell.Controls.Add(chk);[/b] row.Cells.Add(cell); cell = new TableCell(); [b] TextBox txt = new TextBox(); txt.ID = "ed_" + dt.Rows[i]["ItemId"].ToString(); cell.Controls.Add(txt);[/b] row.Cells.Add(cell); cell = new TableCell(); cell.HorizontalAlign = HorizontalAlign.Right; cell.Text = Double.Parse(dt.Rows[i]["Price"].ToString()).ToString("C2", CultureInfo.CreateSpecificCulture("el-GR")); row.Cells.Add(cell); Catalog.Rows.Add(row); } Και έτσι προσπαθώ να τα τσιμπήσω ... > . . . . bool AtLeastOneItemSelected = false; foreach (Control ctrl in PlaceHolder1.Controls) { if (ctrl.GetType() == typeof(CheckBox)) { if ( ((CheckBox)ctrl).Checked ) { //At least one item is selected! AtLeastOneItemSelected = true; break; } } } . . . . Η σελίδα είναι αυτής της μορφής: > <%@ Page Title="" Language="C#" MasterPageFile="~/Site.master" AutoEventWireup="true" CodeFile="Order.aspx.cs" Inherits="Default2" %> <asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" Runat="Server"> </asp:Content> <asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server"> <div id="MainDiv" align="center"> <asp:PlaceHolder ID="PlaceHolder1" runat="server"></asp:PlaceHolder> </div> <br /> <br /> <div id="SendOrderDiv" align="center"> <asp:Button ID="btPlaceOrder" runat="server" Text="Παραγγελία" onclick="btPlaceOrder_Click" /> <asp:Button ID="btCancelOrder" runat="server" Text="Ακύρωση" onclick="btCancelOrder_Click" /> </div> </asp:Content> Ελπίζω να σου έδωσα όλες τις πληροφορίες για να βγάλεις συμπέρασμα ... Σε ευχαριστώ για την πολύτιμη βοήθειά σου ...
παπι Δημοσ. 16 Ιουνίου 2011 Δημοσ. 16 Ιουνίου 2011 Δεν υποτιθεται οτι πρεπει να ειναι σε ενα form για να κανει postback; BTW κανε linq στη βαση για να γλυτωσεις αρκετεεεεεεες γραμμες κωδικα
_tasos Δημοσ. 16 Ιουνίου 2011 Δημοσ. 16 Ιουνίου 2011 Άρα το πρόβλημα σου δεν είναι το ότι δεν "βρίσκεις" τα controls, αλλά το ότι δεν έχουν τις τιμές που έδωσε ο χρήστης. Δεν είδα τον κώδικα σου (ακόμα), αλλά θα πρότεινα το εξής: Να έχεις ενεργοποιημένο το viewstate και η δημιουργία της φόρμας (που φαντάζομαι θα γίνεται κάπου στο Page_Load(...)) να είναι μέσα σε ένα if > protected void Page_Load(object sender, EventArgs e) { if (!this.IsPostBack) { //code to create form... } } Σωστή κ η παρατήρηση για το form, αλλά μάλλον υπάρχει στο master page. Aν δεν υπήρχε δεν νομίζω να έτρεχε καν το btPlaceOrder_Click function.
nspyrou Δημοσ. 16 Ιουνίου 2011 Μέλος Δημοσ. 16 Ιουνίου 2011 Άρα το πρόβλημα σου δεν είναι το ότι δεν "βρίσκεις" τα controls, αλλά το ότι δεν έχουν τις τιμές που έδωσε ο χρήστης. Δεν είδα τον κώδικα σου (ακόμα), αλλά θα πρότεινα το εξής: Να έχεις ενεργοποιημένο το viewstate και η δημιουργία της φόρμας (που φαντάζομαι θα γίνεται κάπου στο Page_Load(...)) να είναι μέσα σε ένα if > protected void Page_Load(object sender, EventArgs e) { if (!this.IsPostBack) { //code to create form... } } Σωστή κ η παρατήρηση για το form, αλλά μάλλον υπάρχει στο master page. Aν δεν υπήρχε δεν νομίζω να έτρεχε καν το btPlaceOrder_Click function. Φίλε _tasos, όσων αφορά το ζήτημα του form, λόγω του οτι η σελίδα κάνει Inherit από την Master page, δεν χρειάζεται να υπάρχει η δήλωση του <form runat="server"> γιατι υπάρχει ήδη όταν η σελίδα γίνεται render. Το πρόβλημα δεν έγκειται στο ζήτημα της σελίδας, σε οτι αφορά το PostBack. To postback γίνεται, και είναι προφανές, γιατί αφενός ο κώδικας των eventhandlers εκτελείται (σε ότι αφορά το submit από το <asp:Button>), και αφετέρου από το flashing που επέρχεται μετά το submit στη σελίδα. Για να σου δώσω μια εικόνα της λογικής της φόρτωσης των controls στην συγκεκριμένη φόρμα, σκέψου το εξής: Οτι, βάσει ενος Query, γίνεται loop μέσα στα rows ενος sorted datatable, ώστε, να δημιουργηθεί ένας πίνακας <table> on-the-fly, ο οποίος έχει προστεθεί στην αρχή του κώδικα στο PlaceHolder container. Αφού αποτυπωθεί το είδος στο αντίστοιχο κελί του πίνακα, προστίθεται, ένα CheckBox και ένα TextBox σε αντίστοιχα κελιά καθώς και η τιμή του είδους. Τα rows ένα προς ένα προστίθενται στον πίνακα ο οποίος είναι ήδη Added στο PlaceHolder. Η δημιουργία της φόρμας γίνεται όπως λες στο Page_Load() με έναν κώδικα ακριβώς όπως τον περιγράφεις: > if (!IsPostBack) { BuildMenu(); // Η ρουτίνα δημιουργίας ... } Και όντως το πρόβλημα είναι οτι δεν επιστρέφονται οι τιμές των server controls όπως συμπεραίνεις. Οποιαδήποτε συμβουλή/γνώμη/πρόταση θα την εκτιμούσα ιδιαίτερα Σ'ευχαριστώ και πάλι για την πολύτιμη βοήθειά σου ...
_tasos Δημοσ. 16 Ιουνίου 2011 Δημοσ. 16 Ιουνίου 2011 Το σχόλιο για το form πήγαινε στον "παπί". Τώρα κάτι παραπάνω δεν μπορώ να σκεφτώ, θα έπρεπε να παίζει. Θα πρέπει να παίξω με λίγο κώδικα για να δω τι γίνεται. Όταν γίνει το postback, τα textboxes και checkboxes στη σελίδα έχουν κρατήσει τις τιμές που είχε δώσει ο χρήστης; Το viewstate είναι ενεργοποιημένο;
nspyrou Δημοσ. 16 Ιουνίου 2011 Μέλος Δημοσ. 16 Ιουνίου 2011 Το σχόλιο για το form πήγαινε στον "παπί". Τώρα κάτι παραπάνω δεν μπορώ να σκεφτώ, θα έπρεπε να παίζει. Θα πρέπει να παίξω με λίγο κώδικα για να δω τι γίνεται. Όταν γίνει το postback, τα textboxes και checkboxes στη σελίδα έχουν κρατήσει τις τιμές που είχε δώσει ο χρήστης; Το viewstate είναι ενεργοποιημένο; H σελίδα μετά το postback περιέχει ακόμα τις τιμές των πεδίων και τα checks των checkboxes. To ViewState μετά την προτροπή σου το ενεργοποίησα. Αυτό που κατάλαβα, είναι οτι,, το PlaceHolder περιέχει στο collection των controls, ένα μόνο Control(!?!).. Υποθέτω οτι είναι το Table ... έτσι έκανα ένα τεστάκι, και το Collection που κάνω τώρα iterate, είναι το PlaceHolder1.Controls[0].Controls ... Αυτό μου δίνει το σύνολο των γραμμών του πίνακα ... συμπερασμάτικά ... επέρχεται η εξής ερώτηση: Υπάρχει η πιθανότητα να μην γίνονται όλα τα controls που περιέχονται στο collection iterate εκτός των first level???? Δηλαδή βάσει των όσων βλέπω υπάρχει πιθανότητα τα content controls του collection, να μην γίνονται enum έστω κι αν είναι containers?? Αν είναι έτσι,, μιλάμε για recursion, και βάσει των όσων έχω, μιλάμε για enumeration κατά: PlaceHolder > Table > Cells > Controls ....??
_tasos Δημοσ. 16 Ιουνίου 2011 Δημοσ. 16 Ιουνίου 2011 Το viewstate δεν πρέπει να είναι ενεργοποιημένο απαραίτητα, π.χ. τα checkboxes και textboxes δεν τη χρειάζονται, Δηλαδή όσα controls είναι τα αντίστοιχα html form elements δεν θέλουν viewstate για να λειτουργήσουν. Αλλά αν έχεις Label, Literal, GridViews, PlaceHolders χρειάζεσαι το viewstate. Όσο αφορά το iteration, ναι έτσι γίνεται. Όπως καταλαβαίνεις είναι λίγο δύσκολο να βρεις έτσι τα controls που θέλεις. Προσωπικά θα χρησιμοποιούσα την FindControl, όπου δίνεις το ID και σου επιστρέφει το control. Εφόσον τα ID τα ορίζεις εσύ νομίζω θα μπορέσεις να πετύχεις αυτό που θέλεις με αυτήν την function.
nspyrou Δημοσ. 16 Ιουνίου 2011 Μέλος Δημοσ. 16 Ιουνίου 2011 Το viewstate δεν πρέπει να είναι ενεργοποιημένο απαραίτητα, π.χ. τα checkboxes και textboxes δεν τη χρειάζονται, Δηλαδή όσα controls είναι τα αντίστοιχα html form elements δεν θέλουν viewstate για να λειτουργήσουν. Αλλά αν έχεις Label, Literal, GridViews, PlaceHolders χρειάζεσαι το viewstate. Όσο αφορά το iteration, ναι έτσι γίνεται. Όπως καταλαβαίνεις είναι λίγο δύσκολο να βρεις έτσι τα controls που θέλεις. Προσωπικά θα χρησιμοποιούσα την FindControl, όπου δίνεις το ID και σου επιστρέφει το control. Εφόσον τα ID τα ορίζεις εσύ νομίζω θα μπορέσεις να πετύχεις αυτό που θέλεις με αυτήν την function. Νομίζω οτι τελικά έχεις δίκιο ... όντως αποδίδω με συγκεκριμένη λογική το id των controls προκειμένου να ξέρω σε ποιο είδος του καταλόγου αναφέρονται chk_[<ItemCode>] για τα checkboxes, ed_[<ItemCode>] για τα textboxes. Επειδή προέρχομαι από τον χώρο των applications κατα κύριο λόγο, αντιλαμβάνεσαι πως το parsing & το enumeration λειτουργούν διαφορετικά στα collections, έπαθα ένα μικρό "πολιτισμικό σοκ", όταν κατάλαβα τι παίχτηκε! Θα κάνω μια αναδιάρθρωση του κώδικα (αναγκαστικά) για να τσιμπήσω τα values κάνοντας χρήση της FindControl(). Τουλάχιστον αυτό δουλεύει όπως θα περίμενε κανείς!! Όπως και να 'χει,, σε ευχαριστώ πολύ για την βοήθεια και για τις πολύτιμες συμβουλές σου. Καλη συνέχεια!
Προτεινόμενες αναρτήσεις
Αρχειοθετημένο
Αυτό το θέμα έχει αρχειοθετηθεί και είναι κλειστό για περαιτέρω απαντήσεις.