Delegate combine

Résolu
Nardo26 Messages postés 37 Date d'inscription samedi 13 janvier 2018 Statut Membre Dernière intervention 1 mars 2021 - 13 mai 2019 à 11:39
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 - 14 mai 2019 à 21:15
Bonjour,

Je ne maitrise pas encore complètement la notion de delegate mais dans mon bout de code,
je fais appel à deux invoke pour mettre à jour 2 objets dans mon IHM.

J'ai vu qu'il y a la possibilité de combiner ces deux appels en un seul.
Comment faire pour combiner ces deux appels, lorsque la méthode SetText doit avoir deux paramètres ?

Merci d'avance.

Private Delegate Sub SetText(obj As Object, txt As String)

Private Sub ProtectedWriteText(obj As Object, txt As String)
    If TypeOf obj Is TextBox Then
        CType(obj , TextBox).Text = txt
    ElseIf TypeOf obj Is Label Then
        CType(obj , Label).Text = txt
    End If
End Sub

Private Sub BtnHomeX_Click(sender As Object, e As EventArgs) Handles BtnHomeX.Click
    Dim thread As New Thread(
        Sub()
            Try
                OperationEnCours = True
                StatusBarLabel1.Text = "Prise d'origine du plateau... axe X"
                Carte.Voie(1).Origine()
                Invoke(New SetText(AddressOf ProtectedWriteText), TxbPosX, "0")  ' TxbPosX.Text = "0"
                Invoke(New SetText(AddressOf ProtectedWriteText), LblConsX, "0") ' LblConsX.Text = TxbPosX.Text
            Catch ex As Exception
                If Carte.PortName = Nothing Then
                    LogTrace.WriteLine("#" + GetCurrentMethod().Name + " : Perte de com avec la carte")
                    MessageBox.Show(Me, " Perte de com avec la carte", "Prise d'origine", MessageBoxButtons.OK, MessageBoxIcon.Error)
                Else
                    LogTrace.WriteLine("#" + GetCurrentMethod().Name + " : " + ex.Message)
                    MessageBox.Show(Me, ex.Message, "Prise d'origine", MessageBoxButtons.OK, MessageBoxIcon.Error)
                End If
            Finally
                OperationEnCours = False
            End Try
        End Sub)
    thread.Start()
End Sub

A voir également:

6 réponses

Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
14 mai 2019 à 21:15
De rien
1
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
13 mai 2019 à 19:00
Bonsoir,
Comment faire pour combiner ces deux appels, lorsque la méthode SetText doit avoir deux paramètres ?

ton délégué a déjà 2 paramètres, du coup je ne comprends pas ta question
0
Nardo26 Messages postés 37 Date d'inscription samedi 13 janvier 2018 Statut Membre Dernière intervention 1 mars 2021
13 mai 2019 à 19:53
Bonsoir,

A la place de ces deux appels consécutifs, n'existe t-il pas un moyen de faire un seul appel ?

Invoke(New SetText(AddressOf ProtectedWriteText), TxbPosX, "0") 
Invoke(New SetText(AddressOf ProtectedWriteText), LblConsX, "0")
0
Nardo26 Messages postés 37 Date d'inscription samedi 13 janvier 2018 Statut Membre Dernière intervention 1 mars 2021
Modifié le 13 mai 2019 à 20:46
En fait je suis tombé sur Delegate.combine mais je ne vois pas comment l'appliquer pour des Delegate avec passage de paramètres. En effet ma méthode ProtectedWriteText a besoin de 2 paramètres (l'objet et le texte qui doit y être appliqué)

Ceci est en C# mais l'idée est là :
https://stackoverflow.com/questions/38300776/referencing-more-than-one-method-using-one-delegate
0
Nardo26 Messages postés 37 Date d'inscription samedi 13 janvier 2018 Statut Membre Dernière intervention 1 mars 2021
Modifié le 13 mai 2019 à 20:20
J'ai un peu remanier mon code et je constate, que le champs du dernier appel à mon délégué n'est pas rafraichit.

   
Private Delegate Sub SetText(sender As Object, s As String)
 
Private Sub UpdateText(obj As Object, txt As String)
    If obj.GetType() Is GetType(TextBox) Then
        Dim t As TextBox = CType(obj, TextBox)
        If t.InvokeRequired Then
            Invoke(New SetText(AddressOf ProtectedWriteText), obj, txt)
        Else
            t.Text = txt
        End If
    ElseIf obj.GetType() Is GetType(Label) Then
        Dim t As Label = CType(obj, Label)
        If t.InvokeRequired Then
            Invoke(New SetText(AddressOf ProtectedWriteText), obj, txt)
        Else
            t.Text = txt
        End If
    End If
End Sub

Private Sub ProtectedWriteText(objAs Object, txt As String)
    If TypeOf sender Is TextBox Then
        CType(sender, TextBox).Text = t
    ElseIf TypeOf sender Is Label Then
        CType(sender, Label).Text = t
    End If
End Sub


Et mes appels dans un thread se font ainsi :

Dim thread As New Thread(
    Sub()
            OperationEnCours = True
            Try
                LogTrace.WriteLine("Mise en position initiale de la machine")
                Carte.SetEnable(True)

                StatusBarLabel1.Text = "Initialisation de la pince..."
                Carte.Voie(3).Origine()
                UpdateText(TxbPosP, "0")
                UpdateText(LblConsP, TxbPosP.Text)


                StatusBarLabel1.Text = "Initialisation de l'altitude du plateau..."
                Carte.Voie(2).Origine() ' Plateau Z
                UpdateText(TxbPosZ, "0")

                StatusBarLabel1.Text = "Initialisation position plateau..."
                Carte.Voie(1).Origine() ' Plateau X            
                UpdateText(TxbPosX, "0")   ' <--- lui est bien rafraichi
                UpdateText(LblConsX, TxbPosX.Text)  ' <--- Mais pas celui-là

                ' … etc, etc...
            Catch ex As Exception
                LogTrace.WriteLine("#" + GetCurrentMethod().Name + " : " + ex.Message)
                MessageBox.Show(ex.Message, "Prise d'origine machine", MessageBoxButtons.OK, MessageBoxIcon.Error)
            End Try
            OperationEnCours = False
        End Sub
        )
        thread.Start()


Le dernier appel à UpdateText() est bien réalisé mais pas l'évènement paint associé au Label LblConsX. Si je sors du TabPage qui contient le label LblConsX et que j'y retourne, la valeur a bien été changée…

Petite remarque : je suis obligé de passer par un délégué pour des Label, des textbox, etc mais curieusement pas pour la barre d'état...
0
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
13 mai 2019 à 21:34
Petite remarque : je suis obligé de passer par un délégué pour des Label, des textbox, etc mais curieusement pas pour la barre d'état...

En effet c'est curieux, c'est quoi son type, statusBar ou StatusStrip?

                UpdateText(TxbPosX, "0")   ' <--- lui est bien rafraichi
                UpdateText(LblConsX, TxbPosX.Text)  ' <--- Mais pas celui-là

Là ça me parait logique, tu ne dois pas pouvoir lire TxbPosX.Text, si tu écris
 UpdateText(LblConsX, "Coucou") 
ça devrait marcher.

Enfin, je ne pense pas que tu aies besoin de combiner des délégués.
InvokeRequired est définie dans la classe Control, donc ceci devrait fonctionner que ce soit un label ou un textbox
Private Sub UpdateText(obj As Object, txt As String)
    If obj.GetType() Is GetType(Control) Then
        Dim t As TextBox = CType(obj, Control)
        If t.InvokeRequired Then
            Invoke(New SetText(AddressOf ProtectedWriteText), obj, txt)
        Else
            ProtectedWriteText(obj, txt)
        End If
    End If
End Sub

0
Nardo26 Messages postés 37 Date d'inscription samedi 13 janvier 2018 Statut Membre Dernière intervention 1 mars 2021
13 mai 2019 à 22:59
C'est un ToolStripStatusLabel… donc il ne possède pas de méthode InvokeRequired.
Je trouve bizarre que pour la plupart des controls on s'assure que l'accès soit réservé au thread propriétaire et que pour d'autres, on n'en tiens pas compte (même dans un backgroundWorker, l'accès direct au ToolStripStatusLabel ne pose pas de problème).

Concernant ton exemple, j'ai l'option 'Strict on' qui m'interdit de faire des conversions implicites de 'Control' en 'TextBox'.


J'avoue que cette série de if/elseif est moche comme tout. Surtout que les blocs de codes sont identiques. C'est seulement l'utilisation du CType (qui me permet d'accéder à la méthode InvokeRequired) qui m'oblige à écrire de cette manière.
Je cherche une feinte...

Concernant le 2ème appel : Au début du try, j'ai 2 appels consécutifs qui fonctionnent très bien.

UpdateText(TxbPosP, "0")
UpdateText(LblConsP, TxbPosP.Text) ' <- cet accès à .Text fonctionne.


En suivant en pas à pas le code, le dernier appel au délégué se fait bien. C'est juste le redraw/paint de mon LblConsX qui ne se fait pas. Dedans j'ai bien la chaine de caractères de TxbPosX.Text
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Whismeril Messages postés 19028 Date d'inscription mardi 11 mars 2003 Statut Non membre Dernière intervention 24 avril 2024 656
14 mai 2019 à 06:27
Ha pardon, j’ai fait une erreur en retapant ton code
Private Sub UpdateText(obj As Object, txt As String)
    If obj.GetType() Is GetType(Control) Then
        Dim t As Control = CType(obj, Control)
        If t.InvokeRequired Then
            Invoke(New SetText(AddressOf ProtectedWriteText), obj, txt)
        Else
            ProtectedWriteText(obj, txt)
        End If
    End If
End Sub


C'est un ToolStripStatusLabel… donc il ne possède pas de méthode InvokeRequired

C’est parce que ce n’est pas un contrôle, il ne dérive pas de la classe Control

Pour l’autre point, là je ne sais pas et je suis sur ma tablette, donc je ne peux pas essayer.

0
Nardo26 Messages postés 37 Date d'inscription samedi 13 janvier 2018 Statut Membre Dernière intervention 1 mars 2021
14 mai 2019 à 08:46
Bonjour Whismeril,

J'ai essayé hier soir, cela ne fonctionne pas mais l'idée est bonne d'y accéder par un cast sur control :

obj.GetType() dans le cas d'un Label va me renvoyer :
{Name ="Label" FullName ="System.Windows.Forms.Label"}

Alors que GetType(Control) lui, contient :
{Name ="Control" FullName="System.Windows.Forms.Control"}



La solution qui fonctionne est celle-ci (et cela me convient ! :) ) :
Private Sub UpdateText(obj As Object, txt As String)
    Dim o As Type = obj.GetType()
    If o Is GetType(Label) Or
       o Is GetType(TextBox) Or
       o Is GetType(cNumBox) Then  ' cNumBox est une classe derivée de TextBox
        Dim t As Control = CType(obj, Control)
        If t.InvokeRequired Then
            Invoke(New SetText(AddressOf ProtectedWriteText), obj, txt)
        Else
            t.Text = txt
        End If
    End If
End Sub

Quand au ToolStripStatusLabel, j'ai eu un plantage sur un accès via un timer (j'ai un 2eme label dans mon StatusStrip qui m'affiche l'heure). Je suppose que, par précaution pour y accéder, il me faudra quand même utiliser UpdateText() dans tous les cas.

Je continue de prospecter sur la cause du non-rafraichissement de mon Label qui est incompréhensible…
Et je garde dans un coin cette histoire de combiner des méthodes dans un délégate (cela risque de me servir plus tard)

Merci de ton aide. :)
0
Nardo26 Messages postés 37 Date d'inscription samedi 13 janvier 2018 Statut Membre Dernière intervention 1 mars 2021
14 mai 2019 à 09:01
Donc la solution que j'ai retenu en tenant compte du StatusStrip est celle-ci :

Private Sub UpdateText(obj As Object, txt As String)
    Dim o As Type = obj.GetType()
    If o Is GetType(Label) Or
       o Is GetType(TextBox) Or
       o Is GetType(cNumBox) Then  ' cNumBox est une classe derivée de TextBox
        Dim t As Control = CType(obj, Control)
        If t.InvokeRequired Then
            Invoke(New SetText(AddressOf ProtectedWriteText), obj, txt)
        Else
            t.Text = txt
        End If
    ElseIf o Is GetType(ToolStripStatusLabel) Then
        Dim t As ToolStripStatusLabel = CType(obj, ToolStripStatusLabel)
        If t.GetCurrentParent.InvokeRequired Then
            Invoke(New SetText(AddressOf ProtectedWriteText), obj, txt)
        Else
            t.Text = txt
        End If
    End If
End Sub
0
Nardo26 Messages postés 37 Date d'inscription samedi 13 janvier 2018 Statut Membre Dernière intervention 1 mars 2021
14 mai 2019 à 19:52
Problème résolu : une erreur de ma part. Je ne mettait pas à jour le bon label. Donc forcément je ne voyais pas le rafraichissement de celui auquel je m'attendais…

Merci Whismeril de t'être penché sur mon pb. :)
0
Rejoignez-nous