none
dynamisches Hinzufügen eines Controls zu einem Div-WebControl RRS feed

  • Frage

  • Hallo,
    ich bin am verzweifeln beim Erstellen eines dynamischen Accordion-Elements.

    Da aber die einzelnen Panels und deren Inhalte erst zur Laufzeit feststehen, muss ich irgendwie ein Control zu einem Div hinzufügen, welches auch erst zur Laufzeit erstellt wird, da die Anzahl variieren kann.
    Nachfolgend das Beispiel eines Accordiongerüsts (von Bootstrap):

        <div class="panel-group" id="accordion">
            <div class="panel panel-default"> 'dynamisch
                <div class="panel-heading">
                    <h4 class="panel-title">
                        <a data-toggle="collapse" data-parent="#accordion" href="#collapse1">Collapsible Group 1</a>
                    </h4>
                </div>
                <div id="collapse1" class="panel-collapse collapse in">
                    <div class="panel-body"> 'dynamisch
                        Inhalt 1
                    </div>
    
                    <div class="panel-body"> 'dynamisch
                        Inhalt 2
                    </div>
    
                    <div class="panel-body"> 'dynamisch
                        Inhalt 3
                    </div>
    
                </div>
            </div>
    
            <div class="panel panel-default"> 'dynamisch
                <div class="panel-heading">
                    <h4 class="panel-title">
                        <a data-toggle="collapse" data-parent="#accordion" href="#collapse2">Collapsible Group 2</a>
                    </h4>
                </div>
                <div id="collapse2" class="panel-collapse collapse">
                    <div class="panel-body"> 'dynamisch
                        Body 2
                    </div>
                </div>
            </div>
    
            <div class="panel panel-default"> 'dynamisch
                <div class="panel-heading">
                    <h4 class="panel-title">
                        <a data-toggle="collapse" data-parent="#accordion" href="#collapse3">Collapsible Group 3</a>
                    </h4>
                </div>
                <div id="collapse3" class="panel-collapse collapse">
                    <div class="panel-body"> 'dynamisch
                        Body 3 
                    </div>
                </div>
            </div>
    
        </div>

    D.h. die Anzahl 'panels' und die darin enthaltenen 'panel-body' (fett markiert) müssen dynamisch erzeugt werden und dem übergeordneten Control zugeordnet werden. Im 'panel-body' sollen dann entsprechend viele UserControls rein. Hierbei muss noch beachtet werden, dass der Verweis im Panel-Header auf das 'panel-collapse'-Element vorhanden sein muss, damit es auf- und zugeklappt werden kann.

    Ich weiß eben nur nicht wie und wäre deshalb für etwas Unterstützung dankbar.
    Ursprünglich sollte es über die AjaxControToolkits realisiert werden, hab das aber wieder verworfen, weil 1. das Usercontrol verhackstückt wurde und 2. dieses Toolkit keinen so guten ruf hat, wenn man sich durch die Foren liest.

    Dann dachte ich mir, ich versuche es mit einem selbst gebastelten AccordionControl, aber hier komme ich nicht weiter, da dieses Control ja Child-Elemente aufnehmen muss.

    Ich hoffe ich konnte mein Anliegen einigermaßen verständlich darlegen und hoffe auf etwas Hilfe.

    @edit

    Als Alternative würde mir jetzt noch eine Brechstangenlösung einfallen, das ganze Gerüst komplett zur Laufzeit mit HTML zu erzeugen. Aber da das UserControl es noch diverse Ereignisse per Buttons auslöst, würde ich darauf gerne verzichten wollen.


    Viele Grüße, Volker





    • Bearbeitet Volker S Mittwoch, 3. August 2016 10:17
    Mittwoch, 3. August 2016 10:03

Antworten

  • Angeregt durch die Idee von Thomas hab ich das Accordion komplett per CodeBehind aufgebaut und es jetzt so gemacht:

    Private Sub Site_Default_Init(sender As Object, e As EventArgs) Handles Me.Init Dim myDB As New dbMonitorEntities Dim intGruppeID As Byte = 0 Dim intGruppeIDAlt As Byte = 0 Dim blNewGroup As Boolean = False Dim blShowGroups As Boolean = True Dim GroupCount As Integer = 0 Dim strGroupName As String = "" Dim CONFIG = From c In myDB.tbl_CLIENT_CONFIG Where c.CLIENT_ID.Equals(Environment.MachineName) And c.VARIABLE.Equals("SHOW_GROUPS") Select c

    If Not CONFIG.Count = 0 Then blShowGroups = CBool(CONFIG.Single.WERT) End If Dim CLIENT = From i In myDB.tbl_CLIENT Order By i.GRUPPE_ID, i.ANZEIGENAME, i.BEZEICHNUNG Select i Dim plcHolder As New PlaceHolder Dim HtmlAccordion As HtmlGenericControl = New HtmlGenericControl("div") Dim HtmlAccGroupPanel As HtmlGenericControl = Nothing Dim HtmlAccGroupPanelHeader As HtmlGenericControl = Nothing Dim HtmlAccPanelCollapse As HtmlGenericControl = Nothing Dim HtmlAccPanelBody As HtmlGenericControl = Nothing Dim ClassAccGroupPanel As String = "panel panel-default" Dim ClassAccGroupPanelHeader As String = "panel-heading" Dim ClassAccGroupPanelTitle As String = "panel-title" Dim ClassAccPanelCollapse As String = "panel-collapse collapse" 'soll ein Panel aufgeklappt sein muss noch zusätzlich die Klasse 'in' mit angefügt werden Dim ClassAccPanelBody As String = "panel-body" 'das Accordion With HtmlAccordion .ID = "accordion" With .Attributes .Add("class", "panel-group") End With End With For Each itm In CLIENT If Not itm.GESPERRT Then Dim ctlMon As Control = LoadControl("/UserControls/MonitorPanel.ascx") Dim ctl As MyControls.MonitorPanel = TryCast(ctlMon, MyControls.MonitorPanel) With ctl .ID = "pnlMonitor" & itm.CLIENT_ID .MONITOR_CLIENT_ID = itm.CLIENT_ID AddHandler .EventsConfigClick, AddressOf EventsConfigClick AddHandler .ReloadPanelClick, AddressOf ReloadPanelClick AddHandler .ClosePanelClick, AddressOf ClosePanelClick AddHandler .SwitchClientClick, AddressOf SwitchClientClick AddHandler .ShowStatusClick, AddressOf ShowStatusClick AddHandler .ShowTrendHourTagClick, AddressOf ShowTrendHourClick AddHandler .ShowTrendDayClick, AddressOf ShowTrendDayClick End With SetPanel(ctl) If blShowGroups Then 'wenn Gruppen angezeigt werden sollen If Not intGruppeID = itm.GRUPPE_ID Then If itm.tbl_GRUPPEN.AKTIV Then If intGruppeID > 0 Then If GroupCount = 1 Then HtmlAccGroupPanelHeader.InnerHtml = strGroupName & " ( 1 Client)" Else HtmlAccGroupPanelHeader.InnerHtml = strGroupName & " ( " & GroupCount & " Clients)" End If End If GroupCount = 0 intGruppeID = itm.GRUPPE_ID strGroupName = itm.tbl_GRUPPEN.GRUPPE_TEXT 'wenn neue Gruppe, dann '1. ein neues Gruppen-Panel erzeugen HtmlAccGroupPanel = New HtmlGenericControl("div") HtmlAccGroupPanel.Attributes.Add("class", ClassAccGroupPanel) 'und dem Accordion hinzufügen HtmlAccordion.Controls.Add(HtmlAccGroupPanel) '2. einen neuen komplett klickbaren Header erzeugen HtmlAccGroupPanelHeader = New HtmlGenericControl("div") With HtmlAccGroupPanelHeader With .Attributes .Add("class", ClassAccGroupPanelTitle & " " & ClassAccGroupPanelHeader & " accPaneHeader") .Add("data-toggle", "collapse") .Add("data-parent", "#accordion") .Add("href", "#cntInhalt_collapse" & itm.tbl_GRUPPEN.GRUPPE_ID) .Add("Style", "Cursor: pointer;") End With .InnerHtml = itm.tbl_GRUPPEN.GRUPPE_TEXT End With 'und dem Gruppen-Panel hinzufügen HtmlAccGroupPanel.Controls.Add(HtmlAccGroupPanelHeader) '3. das Collapse-Panel erzeugen HtmlAccPanelCollapse = New HtmlGenericControl("div") With HtmlAccPanelCollapse With .Attributes .Add("class", ClassAccPanelCollapse) End With .ID = "collapse" & itm.tbl_GRUPPEN.GRUPPE_ID '.ClientID = "collapse" & itm.tbl_GRUPPEN.GRUPPE_ID End With 'und dem Gruppen-Panel hinzufügen HtmlAccGroupPanel.Controls.Add(HtmlAccPanelCollapse) '4. den Panel-Body erzeugen HtmlAccPanelBody = New HtmlGenericControl("div") With HtmlAccPanelBody.Attributes .Add("class", ClassAccPanelBody) End With 'und dem Collapse-Panel hinzufügen HtmlAccPanelCollapse.Controls.Add(HtmlAccPanelBody) End If End If 'das Usercontrol dem Panelbody hinzufügen If itm.tbl_GRUPPEN.AKTIV Then GroupCount += 1 HtmlAccPanelBody.Controls.Add(ctl) End If Else 'wenn keine Gruppen angezeigt werden, dann das Control einfach dem Placeholder hinzufügen plcHolder.Controls.Add(ctl) End If End If Next 'zum Schluss die Controls zur Website hinzufügen If blShowGroups Then 'sonst hat die letzte Gruppe keinen Eintrag
    If GroupCount = 1 Then
    HtmlAccGroupPanelHeader.InnerHtml = strGroupName & " ( 1 Client)"
    Else HtmlAccGroupPanelHeader.InnerHtml = strGroupName & " ( " & GroupCount & " Clients)" End If
    cntMonPanel.Controls.Add(HtmlAccordion)
    Else cntMonPanel.Controls.Add(plcHolder) End If End Sub

    ... und es funktioniert, so wie es soll.
    Gegenüber dem Bootstrap-Original hab ich nur den PanelHeader dahingehend verändert, dass dieser jetzt komplett klickbar ist.

    Vielen Dank an euch beide und ein schönes Wochenende.


    Viele Grüße, Volker


    • Bearbeitet Volker S Freitag, 5. August 2016 09:04
    • Als Antwort markiert Volker S Montag, 8. August 2016 04:44
    Freitag, 5. August 2016 09:02

Alle Antworten

  • Hallo,

    wenn du dich noch in ASP.NET einarbeitest. Kann ich dir ASP.NET MVC empfehlen. MVC ist mein persönliches Lieblings Framework von Microsoft. Keine Entwicklung macht mehr spaß!

    Bei MVC nutzt man keine Controls nur puren HTML/CSS und Javascript somit findest du reichlich an Dokumentationen und Hilfe im Netz. Für die UI ist Bootstrap ausgezeichnet und leicht einzusetzen.

    Als C# Entwickler ist JavaScript kein Thema und jQuery macht das ganze noch einfacher.

    Ausreichend Bücher und Tutorials gibt es dafür auch. 

    Ganz wichtig ist auch das die Web Entwicklung mit der Desktop Entwicklung nicht viel gemeinsam hat.

    in MVC würde ich das einfach im View bauen

    <div class="row">
        <div class="panel-group" id="accordion">
    
            @foreach (var item in collection)
            {
                <div class="panel panel-default">
                    <div class="panel-heading">
                        <h4 class="panel-title">
                            <a data-toggle="collapse" data-parent="#accordion" href="#collapse1">Collapsible Group 1</a>
                        </h4>
                    </div>
                    <div id="collapse1" class="panel-collapse collapse in">
                        @foreach (var item in collection)
                        {
                            <div class="panel-body">
                                'dynamisch
                                Inhalt 1
                            </div>
                        }
                    </div>
                </div>
            }
        </div>
    </div>

    Du solltest dich an das Gerüst von Bootsrap halten

    http://holdirbootstrap.de/javascript/#collapse

    Gruß

    Thomas



    Mittwoch, 3. August 2016 13:27
  • Hallo Thomas,
    vielen Dank für die Antwort.

    Mit MVC hab ich ehrlich gesagt leider nix am Hut.

    Ist der Mixed-Code Razor Syntax?

    Ansonsten halte ich mich schon an die Vorlage von Bootstrap. Da hab ich ja das Snippet her.

    Aber so wie du das aufgezeigt hast, wäre es natürlich am genialsten. Was mich auf die Idee bringt, das ganze mit den entsprechenden Controls zur Laufzeit auch zu erzeugen. Ist zwar ein bissel umständlicher, aber es sollte vllt. auch funktionieren.

    Werd´s mal probieren.

    Vielen Dank für den Anstoß.

    Ansonsten bin ich für weitere Vorschläge offen.


    Viele Grüße, Volker

    Mittwoch, 3. August 2016 16:11
  • Genau das ist Razor.

    In MVC bekommt man ja ein Model an den View und würde das z.B. so abarbeiten

    Mittwoch, 3. August 2016 16:18
  • Net schlecht. Mal so grob geschätzt, wie hoch ist denn der Aufwand von ASP.NET auf MVC umzusteigen oder ein Projekt zu portieren. Das klingt echt interessant.

    Viele Grüße, Volker

    Mittwoch, 3. August 2016 17:12
  • Hallo Volker,

    wenn Du als Ausgang WebForms und als Ziel MVC nimmst, kannst Du alle Webelemente (aspx, master, ...) wegschmeißen und komplett neu aufbauen. Je nachdem, wie dein restlicher Code aufgebaut ist, kannst Du Teile davon sicher weiterverwenden, MVC ist aber halt was komplett anderes als WebForms.

    Ich bin ehrlich gesagt überhaupt kein Freund von MVC und arbeite lieber mit ASP.NET WebPages. Man hat einige der Vorteile, die man bei MVC auch hat (bspw. Razor Syntax, ...) aber dafür auch nicht die Nachteile von MVC.

    Jede der 5 derzeit verfügbaren ASP.NET Technologien (WebForms, MVC, WebPages, WebAPI, Core 1.0, wobei bei letzterem auch MVC wieder mit im Spiel ist) hat ihre Vor- und Nachteile.

    WebForms sind tot und sollten nicht für neue Projekte verwendet werden.

    MVC ist Geschmackssache, man findet viel im Netz dazu

    WebPages sind auch Geschmackssache, man findet nicht ganz so viel dazu, ist eher ein wenig "Back to the roots", was manch erfahrenem Entwickler aber sehr gelegen kommt, da man mehr Kontrolle über das was passiert wo und vor allem wie.

    WebAPI ist eher für Webservices gedacht

    ASP.NET Core 1.0 ist das neueste, hat mit den anderen Ansätzen aber in weiten Teil nicht mehr viel zu tun, wird aber wohl die Zukunft werden, was ASP.NET angeht.

    Ich würde dir empfehlen, dich mal über die ASP.NET Abkömmlinge zu informieren und dann zu entscheiden, was dir eher liegt.

      http://www.asp.net/aspnet

      https://docs.asp.net/en/latest/

     


    Gruß, Stefan
    Microsoft MVP - Visual Developer ASP/ASP.NET
    http://www.asp-solutions.de/ - Consulting, Development
    http://www.aspnetzone.de/ - ASP.NET Zone, die ASP.NET Community


    Mittwoch, 3. August 2016 17:42
    Moderator
  • Das wirklich aufwendig ist das umdecken von WebForms zu MVC und breitet sehr vielen zu Anfang Schwierigkeiten.

    Man bekommt vom Controler nur ein Model sonst nichts.

    Alles andere muss man selbst Entwickeln. Keine Controls, keine Events

    Events nur mit selbst entwickelten JavaScript. Die View Logik ist Komplet von der Server Logik getrennt.

    Der Vorteil ist aber das der View sonst was sein kann. Eine Website, WPF, UWP, Android ...

    Man kommt da zwar schon in den Bereich WebApi aber dieser Übergang ist fliesend.

    Der nachteil ist sich viele weitere Technologien an zu eignen, was wiederum ein Vorteil sein kann.

    Dem Begriff "Man lernt nie aus" werde hier ganz neue Maßstäbe gesetzt :)

    Mittwoch, 3. August 2016 19:12
  • Hallo Stefan,
    danke für die Erleuchtung. Da läuft es mir kalt den Rücken herunter. Bisher war ich nur mit  WebForms zugange. Mal sehen mit was ich die restlichen paar Jahre zubringe.
    Was man allerdings von NET CORE 1.0 so hört, da sollte man wahrscheinlich lieber auf die Version 2.0 warten.
    Vielleicht führt ja MS in ein paar Jahren wieder eine neue, ganz tolle Technologie ein.
    ;)

    Ich denke so ganz grob überpeilt, könnte WebPages ganz interessant sein, vor allem in Bezug auf Razor.


    Viele Grüße, Volker

    Donnerstag, 4. August 2016 05:04
  • Angeregt durch die Idee von Thomas hab ich das Accordion komplett per CodeBehind aufgebaut und es jetzt so gemacht:

    Private Sub Site_Default_Init(sender As Object, e As EventArgs) Handles Me.Init Dim myDB As New dbMonitorEntities Dim intGruppeID As Byte = 0 Dim intGruppeIDAlt As Byte = 0 Dim blNewGroup As Boolean = False Dim blShowGroups As Boolean = True Dim GroupCount As Integer = 0 Dim strGroupName As String = "" Dim CONFIG = From c In myDB.tbl_CLIENT_CONFIG Where c.CLIENT_ID.Equals(Environment.MachineName) And c.VARIABLE.Equals("SHOW_GROUPS") Select c

    If Not CONFIG.Count = 0 Then blShowGroups = CBool(CONFIG.Single.WERT) End If Dim CLIENT = From i In myDB.tbl_CLIENT Order By i.GRUPPE_ID, i.ANZEIGENAME, i.BEZEICHNUNG Select i Dim plcHolder As New PlaceHolder Dim HtmlAccordion As HtmlGenericControl = New HtmlGenericControl("div") Dim HtmlAccGroupPanel As HtmlGenericControl = Nothing Dim HtmlAccGroupPanelHeader As HtmlGenericControl = Nothing Dim HtmlAccPanelCollapse As HtmlGenericControl = Nothing Dim HtmlAccPanelBody As HtmlGenericControl = Nothing Dim ClassAccGroupPanel As String = "panel panel-default" Dim ClassAccGroupPanelHeader As String = "panel-heading" Dim ClassAccGroupPanelTitle As String = "panel-title" Dim ClassAccPanelCollapse As String = "panel-collapse collapse" 'soll ein Panel aufgeklappt sein muss noch zusätzlich die Klasse 'in' mit angefügt werden Dim ClassAccPanelBody As String = "panel-body" 'das Accordion With HtmlAccordion .ID = "accordion" With .Attributes .Add("class", "panel-group") End With End With For Each itm In CLIENT If Not itm.GESPERRT Then Dim ctlMon As Control = LoadControl("/UserControls/MonitorPanel.ascx") Dim ctl As MyControls.MonitorPanel = TryCast(ctlMon, MyControls.MonitorPanel) With ctl .ID = "pnlMonitor" & itm.CLIENT_ID .MONITOR_CLIENT_ID = itm.CLIENT_ID AddHandler .EventsConfigClick, AddressOf EventsConfigClick AddHandler .ReloadPanelClick, AddressOf ReloadPanelClick AddHandler .ClosePanelClick, AddressOf ClosePanelClick AddHandler .SwitchClientClick, AddressOf SwitchClientClick AddHandler .ShowStatusClick, AddressOf ShowStatusClick AddHandler .ShowTrendHourTagClick, AddressOf ShowTrendHourClick AddHandler .ShowTrendDayClick, AddressOf ShowTrendDayClick End With SetPanel(ctl) If blShowGroups Then 'wenn Gruppen angezeigt werden sollen If Not intGruppeID = itm.GRUPPE_ID Then If itm.tbl_GRUPPEN.AKTIV Then If intGruppeID > 0 Then If GroupCount = 1 Then HtmlAccGroupPanelHeader.InnerHtml = strGroupName & " ( 1 Client)" Else HtmlAccGroupPanelHeader.InnerHtml = strGroupName & " ( " & GroupCount & " Clients)" End If End If GroupCount = 0 intGruppeID = itm.GRUPPE_ID strGroupName = itm.tbl_GRUPPEN.GRUPPE_TEXT 'wenn neue Gruppe, dann '1. ein neues Gruppen-Panel erzeugen HtmlAccGroupPanel = New HtmlGenericControl("div") HtmlAccGroupPanel.Attributes.Add("class", ClassAccGroupPanel) 'und dem Accordion hinzufügen HtmlAccordion.Controls.Add(HtmlAccGroupPanel) '2. einen neuen komplett klickbaren Header erzeugen HtmlAccGroupPanelHeader = New HtmlGenericControl("div") With HtmlAccGroupPanelHeader With .Attributes .Add("class", ClassAccGroupPanelTitle & " " & ClassAccGroupPanelHeader & " accPaneHeader") .Add("data-toggle", "collapse") .Add("data-parent", "#accordion") .Add("href", "#cntInhalt_collapse" & itm.tbl_GRUPPEN.GRUPPE_ID) .Add("Style", "Cursor: pointer;") End With .InnerHtml = itm.tbl_GRUPPEN.GRUPPE_TEXT End With 'und dem Gruppen-Panel hinzufügen HtmlAccGroupPanel.Controls.Add(HtmlAccGroupPanelHeader) '3. das Collapse-Panel erzeugen HtmlAccPanelCollapse = New HtmlGenericControl("div") With HtmlAccPanelCollapse With .Attributes .Add("class", ClassAccPanelCollapse) End With .ID = "collapse" & itm.tbl_GRUPPEN.GRUPPE_ID '.ClientID = "collapse" & itm.tbl_GRUPPEN.GRUPPE_ID End With 'und dem Gruppen-Panel hinzufügen HtmlAccGroupPanel.Controls.Add(HtmlAccPanelCollapse) '4. den Panel-Body erzeugen HtmlAccPanelBody = New HtmlGenericControl("div") With HtmlAccPanelBody.Attributes .Add("class", ClassAccPanelBody) End With 'und dem Collapse-Panel hinzufügen HtmlAccPanelCollapse.Controls.Add(HtmlAccPanelBody) End If End If 'das Usercontrol dem Panelbody hinzufügen If itm.tbl_GRUPPEN.AKTIV Then GroupCount += 1 HtmlAccPanelBody.Controls.Add(ctl) End If Else 'wenn keine Gruppen angezeigt werden, dann das Control einfach dem Placeholder hinzufügen plcHolder.Controls.Add(ctl) End If End If Next 'zum Schluss die Controls zur Website hinzufügen If blShowGroups Then 'sonst hat die letzte Gruppe keinen Eintrag
    If GroupCount = 1 Then
    HtmlAccGroupPanelHeader.InnerHtml = strGroupName & " ( 1 Client)"
    Else HtmlAccGroupPanelHeader.InnerHtml = strGroupName & " ( " & GroupCount & " Clients)" End If
    cntMonPanel.Controls.Add(HtmlAccordion)
    Else cntMonPanel.Controls.Add(plcHolder) End If End Sub

    ... und es funktioniert, so wie es soll.
    Gegenüber dem Bootstrap-Original hab ich nur den PanelHeader dahingehend verändert, dass dieser jetzt komplett klickbar ist.

    Vielen Dank an euch beide und ein schönes Wochenende.


    Viele Grüße, Volker


    • Bearbeitet Volker S Freitag, 5. August 2016 09:04
    • Als Antwort markiert Volker S Montag, 8. August 2016 04:44
    Freitag, 5. August 2016 09:02
  • Hallo Volker,
    schau doch mal ob dieser Ansatz/Link Dir hilft:
    http://stackoverflow.com/questions/8936652/dynamically-create-buttons-with-jquery

    Grüße Alexander

    Freitag, 5. August 2016 10:29