Avatar billede fileto Seniormester
03. juli 2004 - 14:28 Der er 14 kommentarer og
1 løsning

Placeholder med dynamisk antal kontroller

Hej
Jeg har lavet en form ved hjælp af en placeholder.
Jeg har et antal checkboxe og en checkbox list for hver af disse.
Jeg har implementeret checkboxene så man ved hjælp af en parameter
kan endre på antallet af checkbox men jeg kan ikke finde ud af
at implementere listboxene så disse også dynamisk kan endre deres antal.
Dette skyldes at jeg har defineret nogle checkboxliscontroller i dette tilfelde
2 (til eksemplet) og dette virker fint men så er jeg jo bundet
af dette antal. Hvis brugeren vil have 3 så skal jeg ind og udvide koden.

Kan nogen fortælle mig hvad der skal til så også antallet af  checkboxlister kan udvides dynamisk?

Min nuværende kode ser således ud :

CheckBoxList lstFeaturedetails1 = new CheckBoxList();
CheckBoxList lstFeaturedetails2 = new CheckBoxList();

for (features=1;features<numberOfSelectedFeatures+1;features++)
{
spacer = space * (features-1);
buttonTopBase = buttonTopBase + space;
// this is a new instance of the cehckbox object?
chkFeature = new CheckBox();
chkFeature.Text = featureName[features-1];
chkFeature.AutoPostBack = true;
chkFeature.ID = "" + ((features-1)+1) + "";
if (searchmethod == "details")
{
chkFeature.CheckedChanged += new EventHandler(FeaturedetailsPannel);
}
plhSearchHolder.Controls.Add(chkFeature);
if (searchmethod == "details")
{
switch (features)
{
case 1:
plhSearchHolder.Controls.Add(lstFeaturedetails1);
break;
case 2:
plhSearchHolder.Controls.Add(lstFeaturedetails2);
break;
}
}
}

private void FeaturedetailsPannel(object sender, System.EventArgs e)
{
CheckBox chkFeature1 = new CheckBox();
chkFeature1 = (CheckBox)sender;

string fId = chkFeature1.ID;
int featix;
featix = Int32.Parse(fId);

//            populate Featuredetail list
string sqlString =    "SELECT sqludtryk WHERE Selection.Id="  + featureId [featix-1];

ArrayList FeaturedetailSelection = new ArrayList();
if (chkFeature1.Checked)
{
MovieDb.MdbPassSqlsCommand(sqlString);
MovieDb.MdbConnectionOpen();
MovieDb.MdbExecuteReader();
pSelection featureDetails = new pSelection();
while (MovieDb.MdbDataRead())
{
featureDetails = new pSelection();
featureDetails.sName = MovieDb.MdbGetString("FeatureDetailname");
featureDetails.sValue = MovieDb.MdbGetInt("Id");
FeaturedetailSelection.Add (featureDetails);
}
MovieDb.MdbConnectionClose();
}
else
{
FeaturedetailSelection.Remove(sender);
}
           
switch (featix)
{
case 1:
lstFeaturedetails1.EnableViewState = true;
lstFeaturedetails1.DataTextField = "sName";
lstFeaturedetails1.DataValueField = "sValue";
lstFeaturedetails1.DataSource = FeaturedetailSelection;
lstFeaturedetails1.DataBind();
break;
case 2:
lstFeaturedetails2.EnableViewState = true;
lstFeaturedetails2.DataTextField = "sName";
lstFeaturedetails2.DataValueField = "sValue"; lstFeaturedetails2.DataSource = FeaturedetailSelection;
lstFeaturedetails2.DataBind();
break;
}
}

Som det ses bruger jeg idag en case sætning til at udfylde 2 lstFeaturedeatails kontroller, det er dette jeg godt vil lave mere dynamisk så jeg ikke skal ind ændre koden hvergang jeg vil have nogle flere checkboxlister.

Er der nogen der har et hint til hvordan dette kan gøres?
Avatar billede snepnet Nybegynder
03. juli 2004 - 16:29 #1
Hej :o)

Er det noget i denne stil du er ude efter :

// til checkboxlisterne
CheckBoxList cbList = null;

// hashtabel til emulering af dynamisk ressource
Hashtable listResource = new Hashtable();

// initialisering af ressourcen
listResource.Add(0, new string[] {"0hej","0med","0dig"});
listResource.Add(1, new string[] {"1hej","1med","1dig"});
listResource.Add(2, new string[] {"2hej","2med","2dig"});

// iteration over ressourcen
foreach(DictionaryEntry de in listResource)
{
    // oprettelse af ny liste
    cbList = new CheckBoxList();

    // angivelse af at data skal hentes fra ressourcen
    cbList.DataSource = (string[])listResource[de.Key];   
   
    // indsættelse af kontrollen
    this.Controls[1].Controls.AddAt(0,cbList);
   
    // databinding
    cbList.DataBind();               
}

Nu er det jo bare et lille uanvendeligt eksempel, men hvis det er lidt i den retning kan jeg udvide det lidt med en måde at lægge data til initialisering uden for koden, hvis du skulle være interesseret.
Avatar billede snepnet Nybegynder
03. juli 2004 - 16:34 #2
Hov - det må du undskylde. Det var ikke så relevant det jeg sendte :o(
Jeg skal nok lave et andet eksempel til dig... Vil de helst have at ressourcen hvor værdierne til listerne kommer fra er et dataset, nogle værdier i web.config, eller ?
Avatar billede fileto Seniormester
03. juli 2004 - 18:36 #3
Det er ikke så vigtigt hvor verdierne kommer fra
det der generer mig er at jeg skal gemme dem i :
CheckBoxList lstFeaturedetails1 = new CheckBoxList();
CheckBoxList lstFeaturedetails2 = new CheckBoxList();

Så jeg dernest er nød til at lave følgende case :

switch (featix)
{
case 1:
lstFeaturedetails1.EnableViewState = true;
lstFeaturedetails1.DataTextField = "sName";
lstFeaturedetails1.DataValueField = "sValue";
lstFeaturedetails1.DataSource = FeaturedetailSelection;
lstFeaturedetails1.DataBind();
break;
case 2:
lstFeaturedetails2.EnableViewState = true;
lstFeaturedetails2.DataTextField = "sName";
lstFeaturedetails2.DataValueField = "sValue"; lstFeaturedetails2.DataSource = FeaturedetailSelection;
lstFeaturedetails2.DataBind();
break;
}
}

Hvis man dog bare kunne sige
CheckBoxList[] lstFeaturedetails1 = new CheckBoxList()[antal];
så ville man kunne udvide antallet af kontroller dynamisk og
så ville mit problem være løst men bryder compileren sig ikke om.

Hvis du har en løsning til hvordan jeg opbevare kontroldataene i en felles container feks en indexer ville jeg være glad.
En anden løsning vil være hvis jeg kunne kopiere indholdet af lstFeaturedetails1 over i lstFeaturedetails. Altså indholdet fra en kontrol over i en anden kontrol af samme type, det ville også hjælpe mig meget på dette område.
Avatar billede snepnet Nybegynder
03. juli 2004 - 21:26 #4
Du kan godt lave et array på den måde du skriver - f.eks. sådan her :

// til checkboxlisterne
CheckBoxList[] cbListArray = new CheckBoxList[5];

// iteration i fohold til antallet af checkboxlister
for(int i=0;i<cbListArray.Length;i++)
{
    // init
    cbListArray[i] = new CheckBoxList();

    // angivelse af at data skal hentes fra ressourcen
    cbListArray[i].DataSource = new string[] {"hej","med","dig"};   
   
    // indsættelse af kontrollen
    this.Controls[1].Controls.AddAt(0,cbListArray[i]);
   
    // databinding
    cbListArray[i].DataBind();               
}
Avatar billede snepnet Nybegynder
03. juli 2004 - 21:35 #5
Du kan også lave en ekstra forekomst af en tilsvarende CheckBoxList - eks :

private CheckBoxList CopyCheckBoxList(CheckBoxList cbList)
{
    CheckBoxList list = new CheckBoxList();
   
    foreach(ListItem li in cbList.Items)
    {
        list.Items.Add(li);
    }
   
    return list;
}
Avatar billede snepnet Nybegynder
03. juli 2004 - 22:05 #6
Der er for øvrigt ikke noget i vejen for at du laver collection af den ene eller anden art, og så laver en indexer i den forbindelse (det er ikke indexeren der holder data - den realiserer bare en lettere adgang til dem).

En indexer kan laves sådan rimelig enkelt - du kan lige få et pricipielt eksempel her :

public class SomeIndexerhungryClass
{
  // et eller andet array
  private int[] someInts = new int[10];

  // og en indexer for adgang til arrayet
  public int this [int index]
  {
    // getter
    get{return someInts[index];}

    // setter
    set{someInts[index]=value;}
  }
}
Avatar billede fileto Seniormester
05. juli 2004 - 13:16 #7
Hej snepnet


Nu har jeg forsøgt at putte et array element i en placeholder.

Koden er denne :

#code start
CheckBoxList[] lstFeaturedetails = new CheckBoxList[5];

for (features=1;features<numberOfSelectedFeatures+1;features++)
{
plhSearchHolder.Controls.Add(lstFeaturedetails[features-1]);
}
#code slut

Men for følgende fejl :

Value cannot be null. Parameter name: child

Når jeg putter en checkboxliste er der ingen problemer.

#code start
CheckBoxList lstFeaturedetails1 = new CheckBoxList();
plhSearchHolder.Controls.Add(lstFeaturedetails1);
#code slut

Hvorfor denne forskel?

Jeg kan få fejlen væk ved at gøre følgende :

#code start
lstFeaturedetails[features-1] = lstFeaturedetails1;
plhSearchHolder.Controls.Add(lstFeaturedetails[features-1]);
#code slut

men så for jeg en ny fejl :
Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.

Er dette noget du kender noget til?.

I øvrigt, post lige et svar for points, og tak for de mange tips :-)
Avatar billede snepnet Nybegynder
05. juli 2004 - 13:58 #8
Hej igen :o)

Første denne :
#code start
CheckBoxList[] lstFeaturedetails = new CheckBoxList[5];
for (features=1;features<numberOfSelectedFeatures+1;features++)
{
  // her bliver du nødt til at tilføje :
  lstFeaturedetails[features-1] = new CheckBoxList();
  // så vil denne virke
  plhSearchHolder.Controls.Add(lstFeaturedetails[features-1]);
}
#code slut

Men denne :
#code start
lstFeaturedetails[features-1] = lstFeaturedetails1;
plhSearchHolder.Controls.Add(lstFeaturedetails[features-1]);
#code slut

Har jeg lidt sværere ved at svare på - så skal jeg se lidt mere kode, men helt generelt får du problemer hvis du får skabt et viewstate udfra et kontroltræ, og så efterfølgende under initialiseringen af en side ændrer på det kontroltræ. På den måde vil det ikke være muligt at retablere dine kontroller.

Et eksempel kunne være :

// i page_load :

// til checkboxlisterne
CheckBoxList[] cbListArray = new CheckBoxList[5];

// iteration i fohold til antallet af checkboxlister
for(int i=0;i<cbListArray.Length;i++)
{
    // init
    cbListArray[i] = new CheckBoxList();

    // angivelse af at data skal hentes fra ressourcen
    cbListArray[i].DataSource = new string[] {"hej","med","dig"};   
   
    // indsættelse af kontrollen
    this.Controls[1].Controls.AddAt(0,cbListArray[i]);
   
    // databinding
    cbListArray[i].DataBind();               
}

// i OnInit

if(IsPostBack)
{
    CheckBoxList cbl = new CheckBoxList();
    cbl.Items.Add("A");
    cbl.Items.Add("B");
    this.Controls.AddAt(2, cbl);
}

På den måde moser du en ekstra kontrol ind i kontroltræet inden viewstate-tracking, hvilket umuliggør muligheder for korrekt retablering.

Jeg håber det gav en lille smule mening, men du må lige spørge igen hvis det er helt sort.

mvh
Avatar billede snepnet Nybegynder
05. juli 2004 - 14:00 #9
Og selv tak for øvrigt - jeg håber du får det til at makke ret :o)
Avatar billede snepnet Nybegynder
05. juli 2004 - 16:06 #10
Fik du det sidste til at virke også.... altså det fra kommentaren pr. 05/07-2004 13:58:11
Avatar billede fileto Seniormester
05. juli 2004 - 16:18 #11
1000 tak, nu spiller det hele bare :-).
End sidte lille ting jeg har gået og funderet over.

Nedenstående er instantiering af et object :
CheckBox chkFeature = new CheckBox();

Men hvad er det når man siger sådan her? :
chkFeature = new CheckBox();
Avatar billede snepnet Nybegynder
05. juli 2004 - 16:41 #12
Det er nøjagtig det samme - den nederste kan du bare kun skrive hvis du et andet sted har angivet at chkFeature er af typen CheckBox. Den vil ikke kunne stå alene.

Hvis det er pga. den med arrayet CheckBox[] checkboxes = new CheckBox[5], hvor det efterfølgende er nødvendigt at lave en checkboxes[x] = new CheckBox(), så er årsagen at du sådan set bare har forberedt et array indeholdende elementer af en specifik type, men du har ikke instatieret nogle af elementerne endnu, hvilket er hvad du gør med checkboxes[x] = new CheckBox();

Er det ok ?
Avatar billede snepnet Nybegynder
05. juli 2004 - 16:49 #13
Denne sætning : CheckBox chkFeature = new CheckBox();
Er sådan set bare en deklarering og en instantiering i samme linie.
Avatar billede fileto Seniormester
05. juli 2004 - 17:34 #14
Ja, det hvar det jeg ville vide.
Du skal have mange tak for hjælpen. :-)
Avatar billede snepnet Nybegynder
05. juli 2004 - 17:35 #15
Det var bestemt så lidt :o)
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