2009-05-07 7 views
4

Désolé, c'est le meilleur sujet que je peux trouver, si je comprenais mieux la solution, je pourrais probablement formuler une meilleure ligne d'objet.Utiliser des délégués pour gérer un événement

J'utilise un contrôle de grille, Super liste, l situé ici:

http://www.codeproject.com/KB/list/outlooklistcontrol.aspx?fid=449232&df=90&mpp=25&noise=3&sort=Position&view=Quick&fr=276

Avant de lire le problème, s'il vous plaît noter que vous pouvez télécharger une petite application de l'échantillon VB.NET 2005, démos problème:

http://dokmanovich.com/Documents/SuperListEvents.zip

Obtenir la réponse à ma question, je l'espère, aidez-moi à comprendre les événements dynamiques mieux dans le contexte de ce que je suis en train d'accomplir .

La grille fonctionne comme ceci: Lorsque vous ajoutez une colonne à la grille, vous spécifiez l'adresse d'un gestionnaire d'événements qui renverra la valeur lors de l'exécution. Dans ce cas, la fonction CC_ItemValueAccessor. Cette dernière fonction sera appelée avec un paramètre d'entrée qui, dans ce cas, est un objet "ToDo". Chaque objet ToDo sera rendu en une seule ligne dans la grille. Le travail de la fonction CC_ItemValueAccessor consiste à renvoyer la valeur de la colonne à afficher par la grille pour la ligne correspondant à l'objet ToDo transmis.

Cela fonctionne bien jusqu'à ce que je le prends à l'étape suivante:

Je veux dynamiquement créer des colonnes au moment de l'exécution. Par exemple, je souhaite afficher la sortie d'une donnée renvoyée suite à l'exécution d'un SQL spécifié par l'utilisateur. En utilisant l'approche statique décrite précédemment, j'ai une fonction columnItemValueAccessor chargée de renvoyer la valeur de chaque colonne dans la grille pour l'objet passé dans la ligne. Maintenant, puisque les colonnes sont déterminées à l'exécution en fonction des résultats SQL retournés, je crois que je dois écrire un gestionnaire générique qui gère toutes les colonnes, détermine le nom de la colonne qui a déclenché cet événement et retourne la valeur de cette colonne l'objet ligne transmis comme seul paramètre. Le problème est que la fonction ItemValueAccessor a une signature qui inclut uniquement l'objet ligne et que je ne connais pas un moyen de déterminer le nom de colonne nécessaire, car toutes les colonnes ont été connectées à la même fonction ItemValueAccessor que la fonction ItemValueAccessor. gestionnaire d'événements.

Je soupçonne que c'est juste une limitation du contrôle et que pour surmonter ce problème je devrais améliorer le contrôle personnalisé sous-jacent, mais cela dépasse probablement mes compétences actuelles car c'est un contrôle avancé écrit en C# et je Suis un gars VB.

Voici le code:

Private Sub AddCcColumn() 
    Dim NewColumn As New BinaryComponents.SuperList.Column("CC", "CC", 110, AddressOf Cc_ItemValueAccessor) 
    _SuperList.Columns.Add(NewColumn) 
End Sub 

Private Function Cc_ItemValueAccessor(ByVal rowItem As Object) As Object 
    Dim ToDo As ToDo = CType(rowItem, SrToDoAndException).ToDo 
    Return ToDo.CCs.ToString 
End Function 

« ---------------------------

Et voici les signatures de la méthode instantiator de Column et la définition du dernier paramètre qui est responsable de la spécification de la procédure qui gère identifie le gestionnaire d'événements chargé de renvoyer la valeur de la colonne.

Public Sub New (nom ByVal As String, légende ByVal As String, largeur ByVal As Integer, ByVal columnItemValueAccessor Comme BinaryComponents.SuperList.ColumnItemValueAccessor) Membre du BinaryComponents.SuperList.Colonne

Sub New Public (objet ByVal comme objet, méthode ByVal comme System.IntPtr) Membre du BinaryComponents.SuperList.ColumnItemValueAccessor


Quelqu'un at-il des suggestions ou suis-je coincé? J'adorerais vraiment utiliser les capacités de regroupement fantaisie de ce contrôle afin que je puisse afficher une sortie dynamique qui permet à l'utilisateur de regrouper la sortie dynamique d'un SQL par n'importe quelle colonne.

J'ai adressé la question à l'auteur sur le site ci-dessus mais il est resté sans réponse. C'est une tentative désespérée de trouver un moyen de le faire.

Merci d'avoir porté avec moi. J'espère que cette question n'est pas rejetée en raison du fait que je parle d'un contrôle par un tiers. Mon espoir est que la réponse réside dans une meilleure compréhension des délégués, un sujet plus universel.

+0

Le commentaire de Lamba est intéressant, mais j'ai besoin de plus d'aide. J'ai créé un exemple de travail, en dépouillant la question à l'essentiel et en ajoutant un commentaire montrant ce qui est nécessaire. Vous pouvez l'obtenir ici si vous êtes enclin: http://dokmanovich.com/Documents/SuperListEvents.zip Sinon, je suis à la recherche de quelque chose betetr que le code pesudo et un point dans une direction générale, depuis que je ne peut pas sembler comprendre par moi-même. J'offre une prime, à partir de 50. – ChadD

Répondre

4

Voici le code de l'approche dynamique:

Private Sub btnDynamic_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnDynamic.Click 

    ListControl1.Columns.Clear() 

    For Each DataCol As DataColumn In _ds.dtbPerson.Columns 
     ' Get the column name in a loop variable - it needs to be in loop scope or this won\'t work properly' 
     Dim colName = DataCol.ColumnName 
     ' Create the function that will be called by the grid' 
     Dim colLambda As ColumnItemValueAccessor = Function(rowItem As Object) General_ItemValueAccessor(rowItem, colName) 
     ' Setup each column in the grid' 
     Dim NewColumn As New BinaryComponents.SuperList.Column(DataCol.ColumnName, DataCol.ColumnName, 220, colLambda) 
     ListControl1.Columns.Add(NewColumn) 
    Next 

End Sub 

Private Function General_ItemValueAccessor(ByVal rowItem As Object, ByVal colName As Object) As Object 
    Dim rowPerson As DataRow = CType(rowItem, DataRow) 
    Return rowPerson.Item(colName).ToString 
End Function 

Voici une amorce rapide sur la façon dont cela fonctionne:

Chaque fois que dans la boucle de la fonction lambda crée une nouvelle fonction de rappel pour chaque colonne qui ressemble à quelque chose comme ceci:

Class Func1 
    Dim colName1 As String = "PersonId" 

    Private Function General_ItemValueAccessor1(ByVal rowItem As Object) As Object 
     Dim rowPerson As DataRow = CType(rowItem, DataRow) 
     Return rowPerson.Item(Me.colName1).ToString 
    End Function 
End Class 

Class Func2 
    Dim colName2 As String = "LastName" 

    Private Function General_ItemValueAccessor2(ByVal rowItem As Object) As Object 
     Dim rowPerson As DataRow = CType(rowItem, DataRow) 
     Return rowPerson.Item(Me.colName2).ToString 
    End Function 
End Class 

... for however many columns you have - 3 in this case. 

Vous devez la variable colName dans la boucle et ne pas utiliser directement juste DataCol.ColumnName dans le lambda. Sinon, lorsque la grille se mettra à appeler les fonctions de rappel, cette variable DataCol sera égale à la dernière valeur de la collection (ou Nothing) pour toutes les fonctions de rappel.

Fondamentalement, il ferait cela et vous ne seriez pas obtenir ce que vous attendiez:

Class Func 
    Dim DataCol1 = DataCol 

    Private Function General_ItemValueAccessor1(ByVal rowItem As Object) As Object 
     Dim rowPerson As DataRow = CType(rowItem, DataRow) 
     Return rowPerson.Item(Me.DataCol1.ColumnName).ToString 
    End Function 

    Private Function General_ItemValueAccessor2(ByVal rowItem As Object) As Object 
     Dim rowPerson As DataRow = CType(rowItem, DataRow) 
     Return rowPerson.Item(Me.DataCol1.ColumnName).ToString 
    End Function 
    ... 

End Class 

espoir qui aide. Bonne chance.

+0

Génial, merci. Ça a marché comme sur des roulettes. J'aurais aimé donner aussi du crédit à Matthew (j'ai voté pour sa réponse), mais c'est toi qui m'a aidé à comprendre et à faire fonctionner ça. Je vous remercie! – ChadD

1

Le problème est que la fonction ItemValueAccessor a une signature qui ne comprend que l'objet de la ligne et je ne sais pas d'un moyen de déterminer quel nom la colonne est nécessaire, car toutes les colonnes ont été raccordées à la même fonction de ItemValueAccessor en tant que gestionnaire d'événement.

Bon, je n'ai pas utilisé ce contrôle dans le passé, et je suis vraiment une personne C#. Mais je pense que vous pouvez être en mesure d'accomplir cela en créant un nouveau lambda function pour chaque colonne. Quelque chose comme:

Private Sub AddCcColumn(ByVal sender As System.Object As System.String) 
    colLambda = (Function(rowItem As Object) Cc_InternalItemValueAccessor(columnName, rowItem)) 
    Dim NewColumn As New BinaryComponents.SuperList.Column("CC", "CC", 110, colLambda) 
    _SuperList.Columns.Add(NewColumn) 
End Sub 

Ensuite, colLambda s'adaptera la signature, tandis que votre Cc_InternalItemValueAccessor interne obtient l'information dont il a besoin. Totalement non testé, mais je pense que l'idée de base fonctionne. J'ai utilisé une fonction lambda, comme Matthew l'a suggéré.

+1

Hmmm. Je sais tout savoir sur les expressions lambda, à part qu'il est nouveau et peut-être lié à LINQ (et aux types anonymes?) Je verrai ce que je peux trouver. Merci pour la réponse. – ChadD

+0

Je pense que j'ai besoin d'un gars VB qui comprend Lambas pour me le donner. – ChadD

Questions connexes