Eigenschaften eines Controlls zur Laufzeit kopieren / clonen

  • VB.NET

Es gibt 20 Antworten in diesem Thema. Der letzte Beitrag () ist von us4711.

    Eigenschaften eines Controlls zur Laufzeit kopieren / clonen

    Hallo,

    ich habe auf einer Form ein DataGridView. Die Eigenschaften weichen sehr vom Standard ab. Nun möchte ich ein zweites DGV zur Laufzeit erstellen, was auch nicht das Problem ist. Ich möchte jedoch, dass das neu erstellte DGV genauso aussieht, wie das, welches sich bereits auf der Form befindet. Relevante Eigenschaften wie Size und Location werden anschließend natürlich ncoh angepasst.
    Einige Seiten im Netz weisen auf den "System.ComponentModel.TypeDescriptor" hin, womit ich es schon versucht habe - leider komme ich damit nicht zurecht. :(

    Wie ist dies möglich?

    Viele Grüße,
    Pry
    Dateien umbenennen und nummerieren - nichts leichter als das!

    Basic File Renamer: 100%
    Klappere die relevanten Eigenschaften einzeln durch:

    VB.NET-Quellcode

    1. DGV2.MyProperty = DGV1.MyProperty

    Oder suchst Du ein

    VB.NET-Quellcode

    1. DGV2 = DGV1.Clone()
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    @4typen:

    VB.NET-Quellcode

    1. Dim TextBox2 As TextBox = New TextBox1
    :D :D :D
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Dann bau Dir eine Routine, die die relevanten Properties / Einträge von dem einen in das andere DGV schaufelt.
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    ich hab mal eine sprachausgabe auf deutsch erstellt, vielleicht hilft dir das ja weiter.
    Also hier wird einfach ein webbrowser zur Laufzeit erstellt:
    1). Ein Projekt mit einem Button und einer TextBox erstellen
    2). Code einfügen:

    VB.NET-Quellcode

    1. Public Class Form1
    2. Dim NewButton As New Button
    3. Dim TranslateBrowser As New WebBrowser
    4. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    5. Me.Controls.Add(TranslateBrowser)
    6. For i As Integer = 0 To 1000000 Step 1
    7. Application.DoEvents()
    8. Next
    9. TranslateBrowser.Document.GetElementById("inputtext").InnerText = TextBox1.text
    10. TranslateBrowser.Navigate("javascript:Default.Service.Translate();")
    11. For i As Integer = 0 To 1000000 Step 1
    12. Application.DoEvents()
    13. Next
    14. TranslateBrowser.Navigate("javascript:T2S.Play();")
    15. End Sub
    16. Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    17. With TranslateBrowser
    18. .Name = "WebTranslate"
    19. .Height = 400
    20. .Width = 400
    21. .Top = 50
    22. .Left = 50
    23. .Hide() 'Wenn du das Objekt sehen willst musst du natürlich diese Zeile durch .Show() ersetzen...
    24. .Navigate("http://www.microsofttranslator.com/")
    25. End With
    26. End Sub
    27. End Class


    also für eine TextBox oder einen Button musst du dann eben oben deklarieren und das mit der with anweisung machen

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Telcrome“ ()

    RodFromGermany schrieb:

    Dann bau Dir eine Routine, die die relevanten Properties / Einträge von dem einen in das andere DGV schaufelt.

    Sorry, aber genau da ist doch das Problem. Wenn ich wüsste, wie ich das anstellen kann, dann würde ich nicht fragen. Tut mir leid, aber das hilft mir leider nicht.

    @Telcrome: Danke, die Erstellung zur Laufzeit ist nicht das Problem. Sondern das clonen der Properties.
    Dateien umbenennen und nummerieren - nichts leichter als das!

    Basic File Renamer: 100%

    Da war noch Debug-Code drin:

    Ich hab' dazu vpr einiger Zeit mal 'ne <Extension> gemacht:

    VB.NET-Quellcode

    1. Imports System.ComponentModel
    2. Module modCloneControl
    3. <Extension()>
    4. Public Function CloneControl(ByVal SourceControl As Control, ByVal Parent As Object) As Control
    5. Try
    6. Dim SourceControlType As Type = SourceControl.GetType()
    7. Dim ClonedControl As Object = TryCast(Activator.CreateInstance(SourceControlType), Control)
    8. Dim SourceControlPropertyDescriptorCollection As PropertyDescriptorCollection = System.ComponentModel.TypeDescriptor.GetProperties(SourceControl)
    9. Dim ClonedControlPropertyDescriptorCollection As PropertyDescriptorCollection = System.ComponentModel.TypeDescriptor.GetProperties(ClonedControl)
    10. For Each pd As PropertyDescriptor In SourceControlPropertyDescriptorCollection
    11. Select Case pd.Name
    12. Case "Parent"
    13. ClonedControl.Parent = Parent
    14. Case "Controls"
    15. If Not SourceControl.Controls Is Nothing Then
    16. For Each SourceControlChild As Control In SourceControl.Controls
    17. ClonedControl.Controls.Add(CloneControl(SourceControlChild, ClonedControl))
    18. Next
    19. End If
    20. Case Else
    21. Dim SourceValue = pd.GetValue(SourceControl)
    22. Dim ClonedValue = pd.GetValue(ClonedControl)
    23. If Not SourceValue Is Nothing AndAlso Not SourceValue.Equals(ClonedValue) Then
    24. pd.SetValue(ClonedControl, pd.GetValue(SourceControl))
    25. End If
    26. End Select
    27. Next
    28. Return ClonedControl
    29. Catch ex As Exception
    30. Return Nothing
    31. End Try
    32. End Function
    33. End Module


    Aufruf dann:

    VB.NET-Quellcode

    1. Dim SourceControl As New DataGridView With {.Text = "Quelle"}
    2. Dim ClonedControl = TryCast(SourceControl.CloneControl(Me), DataGridView)
    3. ClonedControl.Text = "Ziel"


    Merke: JEDES Control hat eine property 'Text' (Nur so nebenbei). Sollte nur dazu dienen, den Erfolg des Clonens zu testen ...
    Geht übrigens auch mit der Datasource .... Habe da aber noch nicht alle Seiteneffekte ausgelotet.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „us4711“ () aus folgendem Grund: If pd.Name = "FirstDisplayedScrollingColumnIndex" Then Stop

    hastedas mal mittm DatagridView ausprobiert?

    hey - was ich mir grade vorstellen könnte:
    man bastelt sich ein UserControl mit einem sonem abstrus eingerichteten DGV drauf. Zur Laufzeit erstellt man sich ein son ucl, pflückt das DGV dort runter und setzt es an seinen richtigen Bestimmungort (einfach Parent-Property ändern).
    Das ucl danach disposen.

    Pry schrieb:

    Sorry, aber genau da ist doch das Problem.

    Sieh Dir den Beitrag von @us4711 an, nutze dies als Anhaltspunkt.
    Übertrage alle Eigenschaften, die Du benötigst. Wenn dann welche fehlen, ergfänzt Du sie.
    Fertich. :thumbsup:
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!

    ErfinderDesRades schrieb:

    hastedas mal mittm DatagridView ausprobiert?

    Ja, mein Beispiel bezieht sich ja auf ein DGV. Wegen der komplexen Struktur ist ja die Codestelle
    If Not SourceValue Is Nothing AndAlso Not SourceValue.Equals(ClonedValue) Then ...
    erforderlich. Es gibt im DGV z.B. die FirstDisplayedScrollingColumnIndex-Eigenschaft. Diese ist bei Neuerstellung des Controls auf den Wert -1 gesetzt. Der für eine Zuweisung gültige Wert liegt aber zwischen 0 und dgv.columns.count-1 und würde bei ungeprüfter Zuweisung eine Exception auslösen. Das gleiche gilt für Default-Werte von Nothing, z.B. bei dgv.Datasource.

    ErfinderDesRades schrieb:

    und kann mir nicht vorstellen, dass die mitgeklont werden.

    Doch, geht. Versuch's doch mal. Ich habe z.B. einige DGV-Column-Klassen entwickelt, die bei Click auf Pos. {-1,-1} über den Headern eine spaltenbezogene Filterzeile einblenden, dern Eingabe direkt auf die als Datasource zugrundeliegende Bindingsource wirken.
    Und dat jeht.
    erstmal ists strict off geproggt, und dann tritt irgendein Fehler auf, und wg TryCatch kriegt man keine Rückmeldung, ob und was sich ereignet hat. Es sieht aus, als ereigne sich nichts.
    Verwende ich das iwie falsch?
    Option Strict On!
    TryCatch ist ein heißes Eisen

    Zum Testen das "Test"-MenüItem klicksen.
    Dateien
    • DeepCloning00.zip

      (40,39 kB, 123 mal heruntergeladen, zuletzt: )

    Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von „ErfinderDesRades“ ()

    Der Fehler tritt bei pd.name="CurrentCell" auf. Fehlermeldung: "Die angegebene Zelle gehört nicht zu diesem DataGridView-Steuerelement." Da scheinen die Eigentumsverhältnisse ungeklärt zu sein. Ich guck' mir das am Wochenende mal an.
    Du darfst natürlich nicht CurrentCell übertragen, sondern deren Index (Row, Col).
    Falls Du diesen Code kopierst, achte auf die C&P-Bremse.
    Jede einzelne Zeile Deines Programms, die Du nicht explizit getestet hast, ist falsch :!:
    Ein guter .NET-Snippetkonverter (der ist verfügbar).
    Programmierfragen über PN / Konversation werden ignoriert!
    Der Inhalt der Property ist ein Verweis auf eine Datagridview-Zelle. Frage ist nur: Warum gibt's den Blinker-Effekt: Geht ... geht nicht. Und es soll ja eine allgemeingültige Lösung sein: Wie erkenne ich, das in diesem Falle nicht der INHALT der Property, sondern der POINTER auf den Inhalt übertragen werden soll.

    us4711 schrieb:

    Wie erkenne ich, das in diesem Falle nicht der INHALT der Property, sondern der POINTER auf den Inhalt übertragen werden soll.
    IMO ist das der Grund, warum man Controls nicht pauschal tief klonen kann: Weils da nämlich kein Patentrezept und allgemeingültige Lösung für gibt.

    Nehmen wir ein datengebundenes Control: Soll nun beim Klonen auch ein Klon der DataSource erstellt werden, oder wird dieselbe DataSource der Klon-Vorlage auch als DataSource des Klons verwendet?

    Flache Kopie ist eindeutig definierbar: einfach den gesamten Speicher des Objekts kopieren - fertig. Referenzen im Klon referenzieren dann eben dieselben Objekte wie die Vorlage.

    Tiefe Kopie ist vieldeutig: Teilweise sind Referenzen zu kopieren, teilweise aber auch die referenzierten Objekte mit-zuklonen.

    wollte man konsequent alle referenzierten Objekte klonen, so würde der Klon ins unermessliche anwachsen, bis du schließlich dein ganzes Betriebssystem geklont hast (denke einfach mal an die "Parent"-Property von Control).