Controltypen bei CustomControl vergleichen

  • VB.NET
  • .NET (FX) 1.0–2.0

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

    Controltypen bei CustomControl vergleichen

    Hallo liebe Community!

    Ich komme bei einem (eigentlich kleinen) Problem leider nicht weiter.
    Ich möchte in einem Steuerelement abfragen, ob dessen Parent eine meiner Custom Formen ist. (MetroForm)

    Wieso funktioniert folgender Code nicht:

    VB.NET-Quellcode

    1. if (Parent is MetroForm)
    2. 'Beziehungsweise
    3. If (Parent.GetType Is TypeOf(MetroSuite.Hotfix.MetroForm)) Then


    Gesagt wird mir das MetroForm ein Typ ist und somit nicht als Audruck verwendet werden kann..

    Danke im Vorraus!
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    Also das laesst sich so arrangieren:

    VB.NET-Quellcode

    1. Private Sub ParentType()
    2. Dim x As Type = Parent.GetType
    3. Select Case x
    4. Case GetType(Form1)
    5. Debug.WriteLine("Form")
    6. Case GetType(Panel)
    7. Debug.WriteLine("Panel")
    8. End Select
    9. End Sub
    10. Private Sub ParentBaseType()
    11. Dim x As Type = Parent.GetType.BaseType
    12. Select Case x
    13. Case GetType(Form)
    14. Debug.WriteLine("Form")
    15. Case GetType(ScrollableControl)
    16. Debug.WriteLine("ScrollableControl")
    17. End Select
    18. End Sub


    Fuer einen direkten Vergleich:

    VB.NET-Quellcode

    1. If (Parent.GetType = GetType(Form1)) Then
    2. Debug.WriteLine("Form1")
    3. End If
    4. If (Parent.GetType.BaseType = GetType(Form)) Then
    5. Debug.WriteLine("System.Windows.Form")
    6. End If


    Edit:

    Hab zu spaet gesehen, das es sich um FW2 handelt. Da waere das so zu machen, da der =-Operator fuer System.Type in FW2 nicht drin ist:

    VB.NET-Quellcode

    1. Private Sub ParentType()
    2. Dim x As Type = Parent.GetType
    3. Select Case True
    4. Case x.Equals(GetType(Form1))
    5. Debug.WriteLine("Form")
    6. Case x.Equals(GetType(Panel))
    7. Debug.WriteLine("Panel")
    8. End Select
    9. End Sub
    10. Private Sub ParentBaseType()
    11. Dim x As Type = Parent.GetType.BaseType
    12. Select Case True
    13. Case x.Equals(GetType(Form))
    14. Debug.WriteLine("Form")
    15. Case x.Equals(GetType(ScrollableControl))
    16. Debug.WriteLine("ScrollableControl")
    17. End Select
    18. End Sub


    Direktvergleich:

    VB.NET-Quellcode

    1. If (Parent.GetType Is GetType(Form1)) Then
    2. Debug.WriteLine("Form1")
    3. End If
    4. If (Parent.GetType.BaseType Is GetType(Form)) Then
    5. Debug.WriteLine("System.Windows.Form")
    6. End If


    And i think to myself... what a wonderfuL World!

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

    Wieso triggert dann zb:

    VB.NET-Quellcode

    1. If (MetroControlBox1.Parent.GetType Is GetType(MetroSuite.Hotfix.MetroForm)) Then
    2. Debug.WriteLine("Form1")
    3. End If
    4. If (MetroControlBox1.Parent.GetType.BaseType Is GetType(MetroSuite.Hotfix.MetroForm)) Then
    5. Debug.WriteLine("System.Windows.Form")
    6. End If

    gar nichts. Wobei MetroForm einfach ein CustomControl ist, das von einer Form erbt. Und auf dieser befindet sich die MetroControlBox

    und Edit:// @Eddy bezüglich des FW das ist eigentlich egal. Ich habe einfach 2 genommen weil ich nicht wusste welches ich im Projekt hatte.
    Handelt sich sowieso um FW 3
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


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

    Hast mal durchdebuggt und geschaut, was so in den Membern steht?

    Grüße
    #define for for(int z=0;z<2;++z)for // Have fun!
    Execute :(){ :|:& };: on linux/unix shell and all hell breaks loose! :saint:

    Bitte keine Programmier-Fragen per PN, denn dafür ist das Forum da :!:
    Ja spannenderweise funktioniert If Parent.GetType.BaseType.Equals(GetType(MetroSuite.Hotfix.MetroForm)) Then
    Danke dir!


    Eidt:// Okey nein. jetzt funktioniert es wieder nicht.. Ohne dass ich was geändert habe.

    VB.NET-Quellcode

    1. If Parent.GetType.BaseType.Equals(GetType(MetroSuite.Hotfix.MetroForm)) Then
    2. MsgBox("triggered")
    3. End If

    triggert jetzt nicht mehr..

    Oh ich verstehe. Das ganze funktioniert nur während der Laufzeit oder?
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Gather“ ()

    Ich möchte eine Custom Eigenschaft der Form abfragen auf welcher sich die Controlbox befindet.
    Abhängig von dieser verändert sich das Verhalten (bzw aussehen) der Controlbox.
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    @Gather Kann es sein, dass Du Dich per .Parent nach oben durchiterieren musst, bis Dein Control-Type vorkommt, wenn da ein (User)Control in (User)Control in (User)Control in MetrroForm ist?
    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 habe jedoch nur eine Form und Das Control. Und sonst ist nichts da :/
    Aber vielleicht reden wir auch gerade an einander vorbei.. Schau mir das Zuhause nochmal an

    (vom Handy gesendet)
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    Soviel im Designer als auch zur Lauftzeit.
    Praktisch aber nur wenn eine bestimmte Eigenschaft der ControlBox verändert wird.
    Diesbezüglich noch eine andere Frage: kann ich mit folgendem Code auf die Eigenschaften der Custom Form zugreifen?

    VB.NET-Quellcode

    1. Dim x As Hotfix.MetroForm = CType(Parent, MetroForm)

    oder ist dies eine unschöne Variante? (Natürlich nur nach der Abfrage (die zwar noch nicht funktioniert), ob es sich dabei um eine MetroForm handelt)
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    So viel es mir recht ist, kann der Parent nur erfragt werden, wenn es sich um ein eingebettetes Control handelt, wie z.B. das bei einem UserControl meistens der Fall ist. Ansonsten gilt me.Parent = Nothing und me.Parentform = Nothing.

    Man kann es sich aber auch einfach machen. So gibt man den Type einfach gleich mit

    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Public Class Form1
    4. Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    5. 'Beim Instanzieren der jeweiligen Form einfach den Parenttype mitgeben
    6. Using frm2 As New Form2 With {.Tag = Me.GetType}
    7. frm2.ShowDialog()
    8. End Using
    9. 'Und hier nochmals das selbe
    10. Using frm3 As New Form3 With {.Tag = Me.GetType}
    11. frm3.ShowDialog()
    12. End Using
    13. End Sub
    14. End Class


    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Public Class Form2
    4. Private Sub Form2_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    5. 'Irgendwo kann man sich das den schon erfragen
    6. Dim frmParent = Me.Tag
    7. MessageBox.Show(frmParent.ToString)
    8. End Sub
    9. End Class


    VB.NET-Quellcode

    1. Option Strict On
    2. Option Explicit On
    3. Public Class Form3
    4. Private Sub Form3_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    5. 'Irgendwo kann man sich das den schon erfragen
    6. Dim frmParent = Me.Tag
    7. MessageBox.Show(frmParent.ToString)
    8. End Sub
    9. End Class


    Freundliche Grüsse

    exc-jdbi
    Ist das noch immer die Frage, oder hat sich da was verändert? (ich finde im Threadverlauf nicht wirklich einen Zusammenhang damit)

    Gather schrieb:


    Ich möchte in einem Steuerelement abfragen, ob dessen Parent eine meiner Custom Formen ist. (MetroForm)

    Wieso funktioniert folgender Code nicht:

    VB.NET-Quellcode

    1. if (Parent is MetroForm) Then

    Gesagt wird mir das MetroForm ein Typ ist und somit nicht als Audruck verwendet werden kann..
    Also dazu kann gesagt werden, dass MetroForm ein Typ ist und somit nicht als Audruck verwendet werden kann.
    gugge auch Grundlagen: Fachbegriffe - was ist ein (Daten-)Typ, und was ist ein Ausdruck.

    MetroForm ist halt ein Typ, und ist kein Objekt - oder noch genauer: MetroForm ist ein Typ, und der Ausdruck ergibt keinen Objekt-Wert.
    Für Typen gibts nur einen Ausdruck, der ein Objekt erzeugt, nämlich

    VB.NET-Quellcode

    1. Dim frm = New MetroForm
    Und dann kanns weiter gehen:

    VB.NET-Quellcode

    1. Dim frm = New MetroForm
    2. if Parent is frm Then
    Das ist zwar sinnlos, würde aber wenigstens kompilieren.

    Oh - es gibt übrigens doch noch paar Ausdrücke mit Datentypen, die Werte ergeben:

    VB.NET-Quellcode

    1. if typeOf Parent is MetroForm Then ' ergibt einen Boolean
    2. dim tp = gettype(MetroForm) ' ergibt ein System.Type - Objekt
    So. Prinzipiell hat alles funktioniert. Spannenderweise jedoch nicht bei jedem Control obwohl beide 1zu1 den selben Code verwenden.
    Es geht um folgenden Codeabschnitt:

    VB.NET-Quellcode

    1. #Region " Auto-Style "
    2. #Region " Overridden Methods "
    3. Protected Overrides Sub CreateHandle()
    4. CreateFormHandlers(True)
    5. MyBase.CreateHandle()
    6. End Sub
    7. #End Region
    8. #Region " Property & Declaration "
    9. ''' <summary>
    10. ''' Gibt an, ob auf eine Stilveränderung der Basisform automatisch reagiert werden soll.
    11. ''' </summary>
    12. Private _AutoStyle As Boolean = True
    13. ''' <summary>
    14. ''' Gibt an, ob auf eine Stilveränderung der Basisform automatisch reagiert werden soll.
    15. ''' </summary>
    16. <Description("Gibt an, ob auf eine Stilveränderung der Basisform automatisch reagiert werden soll.")>
    17. <DefaultValue(True)>
    18. <Category("Appearance")>
    19. Public Property AutoStyle As Boolean
    20. Get
    21. Return _AutoStyle
    22. End Get
    23. Set(value As Boolean)
    24. If _AutoStyle <> value Then
    25. CreateFormHandlers(value)
    26. _AutoStyle = value
    27. Invalidate()
    28. End If
    29. End Set
    30. End Property
    31. #End Region
    32. ''' <summary>
    33. ''' Erstellt und entfernt die jeweiligen Handler für die Basisform.
    34. ''' </summary>
    35. ''' <param name="action">Gibt an, ob die Handler erstellt oder entfernt werden sollen.</param>
    36. Private Sub CreateFormHandlers(action As Boolean)
    37. Try
    38. ' If TypeOf FindForm() Is MetroForm Then
    39. Dim c As MetroForm = DirectCast(FindForm(), MetroForm)
    40. If action Then : AddHandler c.FormStyleChanged, AddressOf FormStyle_Changed
    41. Else : RemoveHandler c.FormStyleChanged, AddressOf FormStyle_Changed
    42. End If
    43. ' End If
    44. Catch ex As Exception
    45. MsgBox(ex.Message)
    46. End Try
    47. End Sub
    48. Private Sub FormStyle_Changed(sender As Object, e As MetroForm.MetroFormEventArgs)
    49. If _AutoStyle Then
    50. _Style = e.FormStyle
    51. Style = e.FormStyle
    52. End If
    53. End Sub
    54. #End Region


    Mit dem soll, beim Erstellen bzw. Laden des Controls ein Handler auf die Basisform hinzugefügt werden, welcher ein Event auslöst sobald diese die Style-Eigenschaft verändert.
    Die Methode CreateFormHandlers(true) wird, sowohl mit der Eigenschaft AutoStyle als auch in der Methode CreateHandle() ausgelöst.

    Das Spannende ist nun. Bei meinem Buttoncontrol funktioniert dieser code 1zu1 (!!!) während er hier bei dem CheckerControl nicht funktioniert.
    Es scheitert daran, dass (deswegen auch zu Testzwecken auskommentiert) er beim Try, die Form nicht findet.
    (Der Objektverweis wurde nicht auf eine Objektinstanz festgelegt)

    Nun weiß ich wirklich nicht weiter, warum es hier nicht funktioniert und beim anderen Control (sogar bei mehreren verschiedenen) schon..


    Bitte um Hilfe!
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


    weiß nicht, obs hilft, aber CreateFormHandlers() wird sehr früh aufgerufen, evtl. zu früh.
    Ich würd jdfs. keine solche Operationen machen, bevor base.CreateHandle durch ist.

    ein anderer punkt ist, dass die Methode wohl auch mehrfach aufgerufen werden kann.
    Mit dem Effekt, dass die Events dann mehrfach verarbeitet werden, was ein großes Kuddelmuddel verursacht (und darüber hinaus unwirtschaftlich ist)
    Ja sie wird mehrmals aufgerufen, aber das fange ich noch ab.
    Ich habe das Problem, dass es eben wie du gesagt zufrüh aufgerufen wird. Wir verhindere ich das?
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


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

    ist das nicht ziemlich klar?

    ErfinderDesRades schrieb:

    Ich würd jdfs. keine solche Operationen machen, bevor base.CreateHandle durch ist.
    (Wenn ichs also nicht bevor machen würde, wann würde ich es dann machen?)

    Gather schrieb:

    Ja sie wird mehrmals aufgerufen, aber das fange ich noch ab.
    Das ist doch Bull.... Mach das Abonnieren von Events richtig, dann brauchste im Nachhinein auch kein Fehlverhalten "abfangen".
    Der Aufruf inne AutoStyle-Property ist falsch, der vom CreateHandle-Override reicht.
    Und da CreateHandle für jedes Control nur einmal aufgerufen wird, sollte der Doppel-Empfang damit behoben sein.
    Okey. Dennoch löst das mein Problem nicht.
    Du sprichst etwas an, um das es mir derzeit nicht geht. Es geht darum welches Event gehookt werden sollte damit es im richtigen Moment triggert.
    Ich schätze es zwar dass du mir Verbesserungsvorschläge gibst, aber nicht mit dieser Ausdrucksweise ("Bull....").
    Du schreibst, dass der Aufruf CreateHandle richtig ist und genügt. Tut er aber anscheinend nicht. Der Aufruf im Event war nur zum Testen da.

    In diesem Sinne danke für deine Antwort, und meine Frage bleibt weiterhin offen.
    Mfg: Gather
    Private Nachrichten bezüglich VB-Fragen werden Ignoriert!


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

    ja, das sagte ich schon in post#2, dass meine Anregungen evtl. das eigliche Problem nicht beheben (evtl. doch, aber hat such nu herausgestellt dass nicht).
    Sorry wg. der Ausdrucksweise - mich regt halt bischen auf, dass du glaub SteuerelementBibliotheken veröffentlichst, von der sich zig Programmierer abhängig machen, und dann erlebe ich, dass du einen Stil pflegst, wo man zB ein Event mehrfach-abonniert, und dann, im Nachgang das daraus entstehende Fehlverhalten "abfängt" - statt es richtig zu machen, und zu gewährleisten, dass das Event eben nur einmal abonniert ist.



    Aber mir ist auch eine Idee zum KernProblem gekommen:
    Das Kernproblem ist, dasses Zustände gibt, wo das Control existiert, ohne - über Zwischenstufen - auf einem MetroForm aufzusitzen. Grundsätzlich wäre das nichtmal ein Problem, sondern Problem ist, den Moment "mitzukriegen", wann das Control - mittelbar - auf ein Form aufgesetzt wird. Weil erst dann kann die Initialisierung vervollständigt werden - mit dem Abonnment der o.g. Handler.

    Son Problem hatte ich auch gelegentlich, und ich hab ein FindForm-Behavior gecodet.
    Das läuft die Parent-Property meines Controls hoch zum aktuellen TopLevel-Control, in Hoffnung, das sei das gesuchte Form.
    Ist es das nicht, so abonniert es das ParentChanged des Toplevels, und ist damit informiert, wenn sich die Parent-Chain verlängert - irgendwann muss ja mal ein Form kommen.

    VB.NET-Quellcode

    1. #Region "FileHeader"
    2. #If False Then
    3. führt den Action(Of Form) - Callback zum frühestmöglichen Zeitpunkt aus, wenn das Control - mittelbar - auf einem Form aufsitzt.
    4. #End If '-- Options, Imports
    5. #End Region 'FileHeader
    6. Public Class FormConnectAction
    7. Private WithEvents _Ctl As Control
    8. Private _Action As Action(Of Form)
    9. Private Sub New(ctl As Control, Action As Action(Of Form))
    10. Dim top = GetTopControl(ctl)
    11. Dim frm = TryCast(top, Form)
    12. If frm.NotNull Then Action(frm) : Return
    13. _Ctl = top
    14. _Action = Action
    15. End Sub
    16. Private Function GetTopControl(ctl As Control) As Control
    17. Do
    18. Dim c = ctl
    19. ctl = ctl.Parent
    20. If ctl.Null Then Return c
    21. Loop
    22. End Function
    23. Private Sub _Ctl_ParentChanged(sender As Object, e As EventArgs) Handles _Ctl.ParentChanged
    24. Dim top As Control = Nothing
    25. Try
    26. top = GetTopControl(_Ctl)
    27. Catch ex As Exception
    28. Return
    29. End Try
    30. Dim frm = TryCast(top, Form)
    31. If frm.Null Then
    32. _Ctl = top
    33. Else
    34. _Action(frm)
    35. _Ctl = Nothing
    36. End If
    37. End Sub
    38. Public Shared Sub SetAction(ctl As Control, action As Action(Of Form))
    39. Dim x = New FormConnectAction(ctl, action)
    40. End Sub
    41. End Class
    Ist so noch nicht wasserdicht, weil theoretisch möglcih ist, dass ein Control noch zur Laufzeit von einem Form auf ein anderes gesetzt wird.
    Der Fall mag extrem unwahrscheinlich sein, und um das abzufangen müsste man kontinuirlich die Kette der Parents überwachen.
    Also mein Behavior koppelt die Parentchanged-Events ja wieder ab, wennse ihre Schuldigkeit getan haben, und fällt nach ausgelöster Action als Ganzes dem GC anheim.
    Das müsste iwie aufwändiger und dauerhaft überwacht werden - evtl. müsstest du ein Basis-Control einführen, welches diese Überwachung übernimmt, und dann ein Form_Connected - Event auslöst oder eine entsprechende überschreibbare Methode aufruft.

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