Avatar billede milbak Nybegynder
21. marts 2006 - 21:23 Der er 17 kommentarer

Dynamiske kontrols

Jeg er ved at implementere en side, hvor man skal kunne udfylde linjer med tre indtastfelter. For enden af hver linje er der en knap, der kan slette linjen med felterne. En anden knap tilføjer en hel ny linje(tre felter med tilhørende slet-knap). Én enkelt linje (tre felter og knap) har jeg implementeret som en control.

Hver control objekt som fremkommer ved et klik på tilføj knappen tilføjes til en arrayliste. Efter tilføj kalder jeg en metode som løber arraylisten igennem og tilføjer controls til en placeholder.

Tilføjelse og præsentation af control i placeholder fungerer perfekt.

Problemet opstår når jeg skal klikker på en fjern knap. Så kaldes en metode som slette control objektet fra arraylisten. Dette fungerer fint. Herefter kalder jeg metoden som løber arraylisten igennem og tilføjer controls til en placeholder (UpdateLoanPlaceholder()). Dette sker, men GUI opdateres ikke i henhold til indholdet i arraylisten. det er kun det objekt der lige er blevet slettet som præsenteres.

Dette er meget mystisk og håber på nogle input til hvordan jeg kan løse problemet og hvordan man bedst arbejder med dynamiske kontrols også når der skal slettes en kontrol og GUi skal opdateres med det samme.

Jeg vil lade koden tale for sig selv.

---------------------------------------

using System;
using System.Collections;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI;
using System.Web.UI.HtmlControls;

namespace xxxxxx.Web.Forms
{

    public class APO300 : GKUserControlBase
    {
        protected Button uiCalculateLoanButton;
        protected Button uiApplyForLoanButton;
        protected Button uiAddLoanButton;
        protected Button uiButton;

        protected PlaceHolder GetArrayContents;

        protected static ArrayList arrayOfLoans = new ArrayList();
        protected static int numberOfLoans = 1;   
   
        protected static Label label;
        protected Label uiNumberOfLoans;


        protected override void OnInit(EventArgs e)
        {           
            this.uiCalculateLoanButton.Click += new EventHandler(uiCalculateLoanButton_Click);
            this.uiApplyForLoanButton.Click += new EventHandler(uiApplyForLoanButton_Click);
            this.uiAddLoanButton.Click += new EventHandler(uiAddLoanButton_Click);
            this.uiButton.Click += new EventHandler(uiButton_Click);
           
            uiNumberOfLoans.Text += "OnInit";
            UpdateLoanPlaceholder();

            base.OnInit(e);
        }


        private void uiAddLoanButton_Click(object sender, EventArgs e)
        {   
            Control c = this.LoadControl("apo300 loan item.ascx");
            string uniqID = System.Guid.NewGuid().ToString();
            c.ID = uniqID;
           
            numberOfLoans = numberOfLoans+1;

            ((APO300LoanItem)c).uiRemoveLoanButton.Click += new EventHandler(uiRemoveLoanButtonThis_Click);
            arrayOfLoans.Add(c);
           
            UpdateLoanPlaceholder();               
        }

        public void uiRemoveLoanButtonThis_Click(object sender, EventArgs e)
        {
            Control senderLoan = (((Button)sender).Parent);
            Control removeItem = null;       
            foreach(Control item in arrayOfLoans)
            {
                if(senderLoan.ID == (((Control)item).ID))
                    removeItem = ((Control)(item));
            }
            if(removeItem != null)
            {
                arrayOfLoans.Remove(removeItem);
                numberOfLoans = numberOfLoans-1;
                //GetArrayContents.DataBind();
            }
            //UpdateLoanPlaceholder();
        }

        private void uiButton_Click(object sender, EventArgs e)
        {
            UpdateLoanPlaceholder();
        }
       

        private void UpdateLoanPlaceholder()
        {       
            int arraySize = arrayOfLoans.Count;
            uiNumberOfLoans.Text += arraySize;

            foreach(Control item in arrayOfLoans)
            {
                GetArrayContents.Controls.Add(item);
            }           
        }
    }
}

----------------------------------------

using System;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;

namespace xxxxx.Web.Forms
{
    public class APO300LoanItem : GKUserControlBase
    {

        public bool IsPrimary = false;
        public string Title = null;
        public bool IsValidInterestRate = true;

        protected HtmlInputControl uiLoanRemainingDebt;
        protected HtmlInputControl uiLoanMonthlyPayment;
        protected HtmlInputControl uiLoanInterestRate;
        public Button uiRemoveLoanButton;


        override protected void OnInit(EventArgs e)
        {
            //uiRemoveLoanButton.Click += new EventHandler(uiRemoveLoanButton_Click);
            base.OnInit(e);
        }


    /*    private void uiRemoveLoanButton_Click(object sender, EventArgs e)
        {
            this.uiLoanInterestRate.Value = "re";
        }
        */
    }
}
Avatar billede snepnet Nybegynder
21. marts 2006 - 21:41 #1
hej :o)

bruger du 1.1 eller 2.0 (eller... kan du benytte 2.0?)

mht. koden du har sendt...
det ser umiddelbart ud som og at alle dine brugere deler de kontroller der ligger i arrayOfLoans.... er det virkelig det du vil?

mvh
Avatar billede snepnet Nybegynder
21. marts 2006 - 21:44 #2
det ville være en mere klassisk løsning - hvis du holdt din arraylist - indeholdende dine loan-objekter - i session, og så udfra indholdet i listen - renderede f.eks. en repeater med de loan-objekter der er i listen - præsenteret som defineret i en template under repeateren.
mvh
Avatar billede milbak Nybegynder
21. marts 2006 - 22:20 #3
jeg er ret ny til ASP og har ikke det store overblik over mulighederne med asp. Jeg mener at det er 2.0.

Kan du evt forklare i detajler, hvordan en bedre implementation ville se ud?
Avatar billede snepnet Nybegynder
22. marts 2006 - 20:33 #4
well... der er for så vidt mange muligheder, men som udgangspunkt er en statisk variabel fælles for alle brugere.
du må lige finde ud af om det er 2.0.... det giver nogle muligheder som ikke er tilstede hvis det er 1.1 - og den måde man laver det på kan være meget forskellig.
mvh
Avatar billede milbak Nybegynder
23. marts 2006 - 09:53 #5
Det er ASP 1.1.

Du har ret i at arrayOfLoans skal være i session.
Avatar billede snepnet Nybegynder
23. marts 2006 - 13:21 #6
ok.

som udgangspunkt synes jeg du skal sørge for at holde dine præsentationskontroller og dine data lidt mere adskildt.

du kunne f.eks. have en liste af lån i session, og så databinde imod dem:
et lille eksempel:

public class Loan
{
  private string m_loanType;
 
  public string LoanType
  {
    get{retrun m_loanType;}
  }

  public Loan(string loanType)
  {
    m_loanType = loanType;
  }
}

en liste af dem kunne du så holde i session - f.eks. med en property på baseklassen:

private ArrayList m_loans;
protected ArrayList Loans
{
  get
  {
    if(m_loans == null)
      m_loans = new ArrayList();
    return m_loans;
  }
  set
  {
    m_loans = value;
  }
}

og du kunne benytte en af "listekontrollerne" til at vise indholdet - her et eksempel med et datagrid:

// i din aspx-fil
<asp:DataGrid id="grid" runat="server" />

// i din kode:
protected void Page_Load(object sender, EventArgs e)
{
  if(!IsPostBack)
  {
    ShowLoans();
  } 
}

protected void ShowLoans()
{
  grid.DataSource = Loans; // din ArrayList property
  grid.DataBind();
}

har du så en metode der tilføjer eller sletter lån - kan du bygge det på følgende måde:

// i en tilføj-lån-knap-klik-eventhandler:
Loan l = new Loan("lånetype");
Loans.Add(l);
ShowLoans(); // kalder metoden der sikrer at listen på webformen viser det der ligger i arraylisten.

datagrid'et er en af flere kontroller du kan benytte til den slags - en anden oplagt mulighed er en repeater, der potentielt kan give dig lidt mere frie hænder hvad layout angår.

mvh
Avatar billede milbak Nybegynder
23. marts 2006 - 15:49 #7
Tak for din hjælp.

Vil dette løse mit problem med at det rigtige indhold af arrayet ikke vises efter at et element er blevet fjernet? Showloans er jo meget lig min UpdateLoanPlaceholder metode. Var problemet med min oprindelige kode mht til visning af elemterner efter fjernelse at jeg brugte en placeholder?
Avatar billede snepnet Nybegynder
23. marts 2006 - 17:32 #8
well.... dynamiske sider kræver altid lidt arbejde ;o) - men det ville være en sikrere model at følge.
prøv at giv det et lille forsøg, og se om du kan få det til at funge på den måde... du må bare spørge her undervejs hvis der er noget der driller.
mvh
Avatar billede milbak Nybegynder
26. marts 2006 - 12:33 #9
Jeg har nu sat arraylisten i session, men nu får jeg en stackoverflow exception når jeg sætter grid.Datasource = arraylisten.
Avatar billede snepnet Nybegynder
26. marts 2006 - 20:06 #10
kan du vise koden som den ser ud nu?
mvh
Avatar billede milbak Nybegynder
28. marts 2006 - 10:16 #11
protected DataGrid ForeignLoansDatagrid;
            protected ArrayList loanArray;

        public ArrayList LoanArray
        {
            get{ return (ArrayList) Session["loanArray"]; }
            set{ Session["loanArray"] = value; }
        }

        private void Page_Load(object sender, System.EventArgs e)
        {
          if(!IsPostBack)
            {
                Session["loanArray"] = new ArrayList();
                UpdateLoanPlaceholder();
            }                 
        }
     
        private void InitializeComponent()
        {   
            this.Load += new System.EventHandler(this.Page_Load);
        }

        protected override void OnInit(EventArgs e)
        {           
            this.uiCalculateLoanButton.Click += new EventHandler(uiCalculateLoanButton_Click);
            this.uiApplyForLoanButton.Click += new EventHandler(uiApplyForLoanButton_Click);
            this.uiAddLoanButton.Click += new EventHandler(uiAddLoanButton_Click);
            //this.uiButton.Click += new EventHandler(uiButton_Click);
           
            InitializeComponent();
            base.OnInit(e);
        }
        private void uiAddLoanButton_Click(object sender, EventArgs e)
        {   
            Control c = this.LoadControl("apo300 loan item.ascx");
            string uniqID = System.Guid.NewGuid().ToString();
            c.ID = uniqID;           
            numberOfLoans = numberOfLoans+1;

            ((APO300LoanItem)c).Title = "L&aring;n " + numberOfLoans;
            ((APO300LoanItem)c).uiRemoveLoanButton.Click += new EventHandler(uiRemoveLoanButtonThis_Click);
            LoanArray.Add(c);           
            UpdateLoanPlaceholder();
        }

        public void uiRemoveLoanButtonThis_Click(object sender, EventArgs e)
        {
            Control senderLoan = (((Button)sender).Parent);
            ArrayList tempLoanArray = LoanArray;
            foreach(Control item in tempLoanArray)
            {
                if(senderLoan.ID == (((Control)item).ID))
                {
                    tempLoanArray.Remove(item);
                    numberOfLoans = numberOfLoans-1;
                    LoanArray = tempLoanArray;   
                    break;
                }
            }
        }

        private void uiButton_Click(object sender, EventArgs e)
        {
            UpdateLoanPlaceholder();
        }       

        private void UpdateLoanPlaceholder()
        {                             
                ForeignLoansDatagrid.DataSource = LoanArray;
        ForeignLoansDatagrid.DataBind();           
        }
}

i ascx-filen står følgende
<asp:DataGrid id="ForeignLoansDatagrid" runat="server" />
hvilket giver et output der ser sådan ud:
Visible UniqueID EnableViewState TemplateSourceDirectory ID HasUIData ClientID IsPostBack
True 73e983c0-29fd-4669-b943-f9f97b14b7e7 True /Forms/APO300 73e983c0-29fd-4669-b943-f9f97b14b7e7 False 73e983c0-29fd-4669-b943-f9f97b14b7e7 True

hvordan får jeg den til at vise de usercontrols der ligger i arrayet og ikke disse værdi-object referencer? Er helt ny til dette datagrid-ting. Kan finde eksempeler for hvordan man uddrager elementer fra et sql træk, men ikke fra et array/Arraylist.
Avatar billede milbak Nybegynder
28. marts 2006 - 12:58 #12
Jeg har nu lavet følgende:

<asp:DataGrid id="ForeignLoansDatagrid" runat="server" autogeneratecolumns="False">
<Columns>
<asp:TemplateColumn>
<ItemTemplate>
<%# ((APO300LoanItem)Container.DataItem).Title %>
</ItemTemplate>
</asp:TemplateColumn>
<asp:TemplateColumn>
<ItemTemplate>
<%# ((APO300LoanItem)Container.DataItem).uiRemoveLoanButton %>
</ItemTemplate>
</asp:TemplateColumn>
</Columns>
</asp:Datagrid>

Mit problem er nu, hvordan jeg kan outputte en Button i en ItemTemplate. Altså som jeg har prøvet i ovenstående, men dette giver kun tekst der referere til objektet. Titlen i ovenstående bliver udskrevet korrekt.
Avatar billede snepnet Nybegynder
28. marts 2006 - 18:00 #13
som nævnt bør du ikke lægge dine kontroller i session på den måde, men de data der skal benyttes til indsætte dem.
du kan ikke sætte en knap ind på den der måde med mindre fra uiRemoveButton returnerer html'en for en knap.
mvh
Avatar billede milbak Nybegynder
28. marts 2006 - 18:13 #14
hvordan viser jeg så control-objekterne i arraylisten i datagridet?
Avatar billede snepnet Nybegynder
28. marts 2006 - 19:31 #15
det vil som sagt være min anbefaling at du ikke gør det, men du kan gøre sådan noget som dette:

<asp:DataGrid id="grid" runat="server" OnItemDataBound="grid_ItemDataBound">
<Columns>
  <asp:TemplateColumn>
    <ItemTemplate>
      <asp:PlaceHolder id="phButtonHolder" runat="server" />
    </ItemTemplate>
  </asp:TemplateColumn>
</Columns>
</asp:DataGrid>

og i koden:
protected void grid_ItemDataBound(object sender, DataGridItemEventArgs e)
{
    if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem)
    {
        APO300LoanItem loanItem = e.Item.DataItem as APO300LoanItem;
        PlaceHolder buttonHolder = e.Item.FindControl("phButtonHolder") as PlaceHolder;
        buttonHolder.Controls.Add(loanItem.uiRemoveLoanButton);
    }
}

mvh
Avatar billede milbak Nybegynder
28. marts 2006 - 20:50 #16
Jeg forstår ikke helt... Hvis jeg kører min Arrayliste i session, så deler brugerne vel ikke de controls der ligger deri?
Avatar billede snepnet Nybegynder
02. april 2006 - 12:29 #17
nej det gør de ikke... men hvad er årsagen til at du udover at gemme de data du danner dine kontroller udfra + selve kontrollerne i session?
mvh
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
IT-kurser om Microsoft 365, sikkerhed, personlig vækst, udvikling, digital markedsføring, grafisk design, SAP og forretningsanalyse.

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester