IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

VB.NET Discussion :

Filtrage multi-critère de Dataviews, sur plusieurs évenements


Sujet :

VB.NET

  1. #1
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 140
    Points : 37
    Points
    37
    Par défaut Filtrage multi-critère de Dataviews, sur plusieurs évenements
    Bonjour le Forum ^^

    Je reviens cette fois pour des conseils de conception.

    Le projet que je réalise est une application de comparaison entre 2 personnages pour un jeu.

    Chaque personnage a donc des caracteristiques propres, pour simplifier je dit juste son niveau (Level), son métier principal (MainJob).
    Chacun peut s'equiper (weapons, head, body, hands, etc...) à l'aide de comboboxs. Les items de ces comboboxs proviennent d'une BDD Access que j'ai importée au préalable dans un DataSet.
    Pour en venir au problème, je ne prendrai pour simplifier que les combobox MainWeapon1 et SubWeapon1.

    La DataTable "Weapon" est composée des colonnes "Names" (clé primaire), "Level", "Rare Tag", "Equippable Jobs", etc... lesquelles seront utilisées pour le filtrage.
    (la colonne "Rare Tag" est une colonne de checkboxs booléennes)
    (la colonne "Equippable Jobs" est une colonne type Textbox où l'utilisateur tape par exemple "WAR/BRD/DRK/PLD" ou "WAR BRD DRK PLD" ou "WAR,BRD,DRK,PLD" j'espère que LIKE n'est pas embété avec le séparateur utilisé :s)


    Ce que je souhaite c'est que si l'utilisateur change de Level ou de MainJob, les DataViews servant de Datasource aux comboboxs des equipements soient re-filtrées correctement.

    Voici mon code :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    Public Class MainWindow
     
        Shared MaxMainLevel As Byte = 85
     
        Private Sub MainWindow_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Me.FoodTableAdapter.Fill(Me.DataSet.Food)
            Me.WeaponTableAdapter.Fill(Me.DataSet.Weapon)
            Me.AmmoTableAdapter.Fill(Me.DataSet.Ammo)
            Me.RangedTableAdapter.Fill(Me.DataSet.Ranged)
            Me.HeadTableAdapter.Fill(Me.DataSet.Head)
            Me.NeckTableAdapter.Fill(Me.DataSet.Neck)
            Me.HandsTableAdapter.Fill(Me.DataSet.Hands)
            Me.BodyTableAdapter.Fill(Me.DataSet.Body)
            Me.RingTableAdapter.Fill(Me.DataSet.Ring)
            Me.EarTableAdapter.Fill(Me.DataSet.Ear)
            Me.WaistTableAdapter.Fill(Me.DataSet.Waist)
            Me.BackTableAdapter.Fill(Me.DataSet.Back)
            'TODO*: cette ligne de code charge les données dans la table 'DataSet.Legs'. Vous pouvez la déplacer ou la supprimer selon vos besoins.
            Me.LegsTableAdapter.Fill(Me.DataSet.Legs)
            'TODO*: cette ligne de code charge les données dans la table 'DataSet.Feet'. Vous pouvez la déplacer ou la supprimer selon vos besoins.
            Me.FeetTableAdapter.Fill(Me.DataSet.Feet)
            Me.Damage_TypesTableAdapter.Fill(Me.DataSet.Damage_Types)
            Me.Skills_ListTableAdapter.Fill(Me.DataSet.Skills_List)
            Me.Jobs_ListTableAdapter.Fill(Me.DataSet.Jobs_List)
     
            Dim MainJob1View As DataView = New DataView(Me.DataSet.Jobs_List)
            MainJob1View.Sort = "Jobs ASC"
            Me.MainJob1.DataSource = MainJob1View
            Me.MainJob1.DisplayMember = "Jobs"
            Dim SubJob1View As DataView = New DataView(Me.DataSet.Jobs_List)
            SubJob1View.RowFilter = "Jobs <>'" & Me.MainJob1.Text & "'"
            SubJob1View.Sort = "Jobs ASC"
            Me.SubJob1.DataSource = SubJob1View
            Me.SubJob1.DisplayMember = "Jobs"
            Me.SubJob2.DataSource = SubJob2View
            Me.SubJob2.DisplayMember = "Jobs"
            Me.SubJob1.Text = "No SubJob"
     
            Dim MainWeapon1View As DataView = New DataView(Me.DataSet.Weapon)
            MainWeapon1View.Sort = "Names ASC"
            Me.MainWeapon1.DataSource = MainWeapon1View
            Me.MainWeapon1.DisplayMember = "Names"
            Dim SubWeapon1View As DataView = New DataView(Me.DataSet.Weapon)
            SubWeapon1View.Sort = "Names ASC"
            Me.SubWeapon1.DataSource = SubWeapon1View
            Me.SubWeapon1.DisplayMember = "Names"
            Me.MainWeapon1.Text = Nothing
            Me.SubWeapon1.Text = Nothing
     
            Me.MainLevel1.Maximum = MaxMainLevel
            Me.MainLevel1.Value = Me.MainLevel1.Maximum
            Me.SubLevel1.Maximum = Math.Floor(Me.MainLevel1.Maximum / 2)
            Me.SubLevel1.Value = Math.Floor(Me.MainLevel1.Value / 2)
        End Sub
     
        Private Sub MainLevel1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MainLevel1.ValueChanged
            Me.SubLevel1.Maximum = Math.Floor(Me.MainLevel1.Value / 2)
           UpdateEquip1List()
        End Sub
     
        Private Sub MainJob1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MainJob1.TextChanged
            Dim SubJob1View As DataView = New DataView(Me.DataSet.Jobs_List)
            SubJob1View.RowFilter = "Jobs <>'" & Me.MainJob1.Text & "'"
            SubJob1View.RowStateFilter = DataViewRowState.CurrentRows
            Me.SubJob1.DataSource = SubJob1View
            Me.SubJob1.DisplayMember = "Jobs"
            Me.SubJob1.Text = "No SubJob"
          UpdateEquip1List()
        End Sub
     
        Private Sub MainWeapon1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MainWeapon1.TextChanged
          UpdateEquip1List()
        End Sub
     
        Private Sub SubWeapon1_TextChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubWeapon1.TextChanged
          UpdateEquip1List()
        End Sub
     
        Private Sub UpdateEquip1List()
            With Me.DataSet.Weapon.FindByNames(Me.MainWeapon1.Text)
                If .Equippable_Jobs.IndexOf(Me.MainWeapon1.Text) < 0 Or .Level > Me.MainLevel1.Value Then
                    Me.MainWeapon1.Text = Nothing
                End If
            End With
            With Me.DataSet.Weapon.FindByNames(Me.SubWeapon1.Text)
                If .Equippable_Jobs.IndexOf(Me.SubWeapon1.Text) < 0 Or .Level > Me.MainLevel1.Value Then
                    Me.SubWeapon1.Text = Nothing
                End If
            End With
     
            ' If MainWeapon1_TextChanged Or MainLevel1_ValueChanged
            Dim SubWeapon1View As DataView = New DataView(Me.DataSet.Weapon)
            '        SubWeapon1View.RowFilter = "NOT( Names = '" & Me.MainWeapon1.Text & "' AND 'Rare Tag' = 'True' ) AND 'Equippable Jobs' LIKE '*" & Me.MainJob1.Text & "*' AND Level <= '" & Me.MainLevel1.Value & "'"
            SubWeapon1View.RowFilter = "Names <> '" & Me.MainWeapon1.Text & "' AND 'Equippable Jobs' LIKE '*" & Me.MainJob1.Text & "*'"
            SubWeapon1View.RowStateFilter = DataViewRowState.CurrentRows
            Me.SubWeapon1.DataSource = SubWeapon1View
            Me.SubWeapon1.DisplayMember = "Names"
     
            ' If SubWeapon1_TextChanged Or MainLevel1_ValueChanged
            Dim MainWeapon1View As DataView = New DataView(Me.DataSet.Weapon)
            '        MainWeapon1View.RowFilter = "NOT( Names = '" & Me.SubWeapon1.Text & "' AND 'Rare Tag' = 'True' ) AND 'Equippable Jobs' LIKE '*" & Me.MainJob1.Text & "*' AND Level <= '" & Me.MainLevel1.Value & "'"
            MainWeapon1View.RowFilter = "Names <> '" & Me.SubWeapon1.Text & "' AND 'Equippable Jobs' LIKE '*" & Me.MainJob1.Text & "*'"
            MainWeapon1View.RowStateFilter = DataViewRowState.CurrentRows
            Me.MainWeapon1.DataSource = MainWeapon1View
            Me.MainWeapon1.DisplayMember = "Names"
     
        End Sub
     
        Public Sub UpdateEquip2List()
     
        End Sub
     
        ...
     
    End Class
    Les comboboxs MainJob1/SubJob1 et MainWeapon1/SubWeapon1 sont mutuellement exclusives, c'est pour ca que l'on m'avait conseillé d'utiliser des dataviews d'une même table, filtrées indépendamment l'une de l'autre.
    Je réutilise le principe ici, mais de façon étendue à une trentaine de comboboxs, dont certaines (comme les Main/Sub weapons présentées ci-dessus) sont mutuellement exclusives.
    L'exemple ci-dessus signifie qu'un personnage ne peut s'equiper dans chaque main de 2x la même arme, si cette arme est estampillée "Rare" dans la BDD; ET que l'utilisateur ne peut trouver dans les listes déroulantes des comboboxs Main/Subweapons que les armes dont le niveau est inférieur à celui de leur perso, ET dont le job du perso est parmi celles de l'arme dans le DataTable Weapon.



    Le code présenté ne fonctionne pas:

    1. InnerException au chargement à cause de la procédure UpdateEquipList()...
    Je ne vois pas du tout qu'est ce que ma proc a de mal tourné... normalement cette proc n'est appelée QUE sur les événements de changements du contenu des comboboxs ... pourquoi planter au chargement ?

    2. la string pour RowFilter semble ne pas fonctionner: celle commentée est la vraie, celle du dessous me servait de deboguage... le résultat est le même: comboboxs toujours vides

    3. Chacune de mes datatables ont minimum 300lignes sur 40 colonnes, je ne sait pas si la conception que j'ai adopté est la bonne en termes de performance? Parce que si je lis mon code correctement, il va réactualiser les listes de mes 30 comboboxs à la moindre incrémentation de MainLevel1 ou MainJob1... ca fait mal Docteur ?


    N'hésitez pas si ce n'est pas clair.

    Merci d'avance pour vos réponses.

  2. #2
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 140
    Points : 37
    Points
    37
    Par défaut
    Après plusieurs heures à chercher d'où vient cette InnerException: NullReference de mes 2... je viens de découvrir quelquechose d'absolument illogique :

    Lors du déboguage Pas à pas détaillé, je m'aperçois que VB2008 commence par parser........... ma Sub UpdateEquipList en 1er O.O !!??

    Or mes comboboxs MainLevel et MainWeapon sont initialisées dans la procédure Sub MainWindow_Load...

    Résultat: ben forcément UpdateEquipList traite avec des données fausses non initialisées au chargement.... Les espions montrent en effet que :
    MainWeapon1.Text = "System.Data.DataRowView" (au lieu de la 1ère valeur de la liste par défaut... J'ai rajouté une init Me.MainWeapon1.Text=Nothing mais ca change rien au probleme) lorsque VB traite UpdateEquipList().

    Quelqu'un pourrait-il m'expliquer le schmilblick svp ? en clair, ma question est : Pourquoi VB2008 parse-t-il les procédures à l'envers ?? et du coup ce serait quoi la soluce, coder à l'envers aussi lol ?

    EDIT :
    Je crois que j'ai trouvé d'où ca vient...

    VB apparemment execute Form1.Designer.vb en 1er, avant Form1.vb où se trouve le code cidessus.

    Or j'ai cherché dans Form1.Designer.vb les déclarations relatives aux comboboxs MainLevel1/2 et MainJob1/2.....pour découvrir ceci:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    Me.MainLevel1.Minimum = New Decimal(New Integer() {1, 0, 0, 0})
    Ce qui signifie un changement de la valeur du combobox MainLevel1 (au chargement), lequel est considéré comme un évenement. Ce qui déclenche ma sub MainLevel1_ValueChanged dans Form1.vb, laquelle appelle UpdateEquipList(), laquelle se retrouve "les doigts dans le trou" avec des variables non initialisées...

    Le problème est que je ne peux rien faire dans le Designer.vb : il écrase n'importe quelle modif faite avant chaque éxecution...
    Je ne sait pas non plus comment empecher a l'execution du Designer.vb de trigger mes evenements de comboboxs...

    EDIT2: bon j'en ai marre et jsuis naze.... je testerai demain avec les évenements _Validated au lieu de _TextChanged ou _ValueChanged...

  3. #3
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    Citation Envoyé par Masamunai Voir le message
    VB apparemment execute Form1.Designer.vb en 1er, avant Form1.vb où se trouve le code cidessus.
    La première chose exécutée dans ta classe est le constructeur (Sub New), qui appelle lui-même la méthode InitializeComponent qui contient tout le code du designer. C'est seulement lors de l'affichage de la form (Show ou ShowDialog) que l'évènement Load est déclenché, et donc ta méthode MainWindow_Load.

    Citation Envoyé par Masamunai Voir le message
    Le problème est que je ne peux rien faire dans le Designer.vb : il écrase n'importe quelle modif faite avant chaque éxecution...
    Tu n'es pas supposé le modifier... d'ailleurs il doit y avoir un commentaire qui le dit

    Citation Envoyé par Masamunai Voir le message
    Je ne sait pas non plus comment empecher a l'execution du Designer.vb de trigger mes evenements de comboboxs...
    Tu pourrais l'empêcher, en définissant toi même le constructeur et en enlevant l'appel à InitializeComponent... Mais ça n'aurait aucun intérêt : tu te retrouverais avec une Form vide, vu que c'est InitializeComponent qui crée et ajoute les contrôles


    Le plus simple pour ton problème c'est que tu initialises une variable boolean à la fin de ton MainWindow_Load, et que tu testes cette variable dans tes gestionnaires d'évènement. Si elle vaut false, tu sors sans rien faire

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    Private _isInitialized As Boolean
     
    Private Sub MainWindow_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
     
        ...
     
        _isInitialized = True
     
    End Sub
     
        Private Sub MainLevel1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MainLevel1.ValueChanged
     
            If Not _isInitialized Then
                Return
            End If
     
            Me.SubLevel1.Maximum = Math.Floor(Me.MainLevel1.Value / 2)
           UpdateEquip1List()
        End Sub

    Sinon, tu peux aussi définir les gestionnaires d'évènement manuellement au lieu de le faire dans le designer. Comme ça tu es sûr qu'ils ne seront pas appelés avant que tout soit prêt...

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    AddHandler MainLevel1.ValueChanged, AddressOf MainLevel1_ValueChanged
    AddHandler MainJob1.TextChanged, AddressOf MainJob1_TextChanged

  4. #4
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 140
    Points : 37
    Points
    37
    Par défaut
    Bonjour...

    J'ai essayé plusieurs "sauces"... et j'avoue que je n'arrive pas à obtenir le comportement souhaité

    A chaque fois dès que je trouve une solution à l'un des problèmes, cela "casse" les autres...

    Pour résumer, les 3 principaux cas sont:
    - l'initialisation;
    - la mutualité exclusive bidirectionnelle entre les contenus des listes déroulantes cbx MainWeapon1 et SubWeapon1;
    - les valeurs courantes dans les parties éditables de ces mêmes cbx.

    (le 4e cas pourrait se traiter à part : la réactualisation des listes déroulantes et reset valeurs courantes de ces cbx.)

    Quelqu'un pourrait-il m'aider avant que je devienne chauve s.v.p. ?
    Images attachées Images attachées  

  5. #5
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 140
    Points : 37
    Points
    37
    Par défaut
    Ca y est je suis chauve après 2 jours a m'arracher les cheveux...

    J'ai ENFIN réussi à obtenir les comportements souhaités avec le code suivant (utilisant de façon systématique la variable IsInitialized suggérée par Tomlev) :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    Public Class MainWindow
     
        Private MaxMainLevel As Byte = 85
        Private IsInitialized As Boolean = False
     
        Private Sub MainWindow_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
     
            'TODO*: cette ligne de code charge les données dans la table 'DataSet.Weapon'. Vous pouvez la déplacer ou la supprimer selon vos besoins.
            Me.WeaponTableAdapter.Fill(Me.DataSet.Weapon)
            Me.WeaponDataGridView.Sort(NamesDataGridViewTextBoxColumn12, 
            'TODO*: cette ligne de code charge les données dans la table 'DataSet.Jobs_List'. Vous pouvez la déplacer ou la supprimer selon vos besoins.
            Me.Jobs_ListTableAdapter.Fill(Me.DataSet.Jobs_List)
     
     
            Dim MainJob1View As DataView = New DataView(Me.DataSet.Jobs_List)
            Me.MainJob1.DataSource = MainJob1View
            Me.MainJob1.DisplayMember = "Jobs"
            Dim MainJob2View As DataView = New DataView(Me.DataSet.Jobs_List)
            Me.MainJob2.DataSource = MainJob2View
            Me.MainJob2.DisplayMember = "Jobs"
     
            Me.MainLevel1.Maximum = MaxMainLevel
            Me.MainLevel2.Maximum = MaxMainLevel
            Me.MainLevel1.Value = Me.MainLevel1.Maximum
            Me.MainLevel2.Value = Me.MainLevel2.Maximum
            Me.SubLevel1.Maximum = Math.Floor(Me.MainLevel1.Maximum / 2)
            Me.SubLevel2.Maximum = Math.Floor(Me.MainLevel2.Maximum / 2)
            Me.SubLevel1.Value = Math.Floor(Me.MainLevel1.Value / 2)
            Me.SubLevel2.Value = Math.Floor(Me.MainLevel2.Value / 2)
     
            Dim MainWeapon1View As DataView = New DataView(Me.DataSet.Weapon)
            MainWeapon1View.RowFilter = "( [Equippable Jobs] LIKE '*" & Me.MainJob1.Text & "*' OR [Equippable Jobs] LIKE 'ALL' ) AND Level <= '" & Me.MainLevel1.Value & "'"
            MainWeapon1View.RowStateFilter = DataViewRowState.CurrentRows
            Me.MainWeapon1.DataSource = MainWeapon1View
            Me.MainWeapon1.DisplayMember = "Names"
            Me.MainWeapon1.ResetText()
            Me.MainWeapon1.Tag = ""
            Dim SubWeapon1View As DataView = New DataView(Me.DataSet.Weapon)
            SubWeapon1View = New DataView(Me.DataSet.Weapon)
            SubWeapon1View.RowFilter = "( [Equippable Jobs] LIKE '*" & Me.MainJob1.Text & "*' OR [Equippable Jobs] LIKE 'ALL' ) AND Level <= '" & Me.MainLevel1.Value & "'"
            SubWeapon1View.RowStateFilter = DataViewRowState.CurrentRows
            Me.SubWeapon1.DataSource = SubWeapon1View
            Me.SubWeapon1.DisplayMember = "Names"
            Me.SubWeapon1.ResetText()
            Me.SubWeapon1.Tag = ""
            Dim MainWeapon2View As DataView = New DataView(Me.DataSet.Weapon)
            MainWeapon2View.RowFilter = "( [Equippable Jobs] LIKE '*" & Me.MainJob2.Text & "*' OR [Equippable Jobs] LIKE 'ALL' ) AND Level <= '" & Me.MainLevel2.Value & "'"
            MainWeapon2View.RowStateFilter = DataViewRowState.CurrentRows
            Me.MainWeapon2.DataSource = MainWeapon2View
            Me.MainWeapon2.DisplayMember = "Names"
            Me.MainWeapon2.ResetText()
            Me.MainWeapon2.Tag = ""
            Dim SubWeapon2View As DataView = New DataView(Me.DataSet.Weapon)
            SubWeapon2View = New DataView(Me.DataSet.Weapon)
            SubWeapon2View.RowFilter = "( [Equippable Jobs] LIKE '*" & Me.MainJob2.Text & "*' OR [Equippable Jobs] LIKE 'ALL' ) AND Level <= '" & Me.MainLevel2.Value & "'"
            SubWeapon2View.RowStateFilter = DataViewRowState.CurrentRows
            Me.SubWeapon2.DataSource = SubWeapon2View
            Me.SubWeapon2.DisplayMember = "Names"
            Me.SubWeapon2.ResetText()
            Me.SubWeapon2.Tag = ""
     
            IsInitialized = True
        End Sub
     
     
        '----------------------------------   SETUP 1 SECTION   ------------------------------------------
     
        '--- Equipments Sub-Section ---
     
        Private Sub MainJob1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MainJob1.TextChanged
            Dim SubJob1View As DataView = New DataView(Me.DataSet.Jobs_List)
            SubJob1View.RowFilter = "Jobs <>'" & Me.MainJob1.Text & "'"
            SubJob1View.RowStateFilter = DataViewRowState.CurrentRows
            Me.SubJob1.DataSource = SubJob1View
            Me.SubJob1.DisplayMember = "Jobs"
            Me.SubJob1.Text = "No SubJob"
     
            UpdateEquip1List()
     
        End Sub
     
        Private Sub MainLevel1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MainLevel1.ValueChanged
            Me.SubLevel1.Maximum = Math.Floor(Me.MainLevel1.Value / 2)
            UpdateEquip1List()
        End Sub
     
        Private Sub MainWeapon1_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles MainWeapon1.Leave
            If Me.MainWeapon1.Text = "" Then
                Me.MainWeapon1.Tag = Me.MainWeapon1.Text
                UpdateEquip1List()
            Else : Me.MainWeapon1.SelectAll()
            End If
            'TODO: Si le texte tapé lorsque l'utilisateur quitte la combobox n'existe pas
            'dans la liste déroulante courante (ou ne déclenche pas l'event SelectedIndexChanged),
            'alors SelectAll + afficher bulle d'erreur
        End Sub
     
        Private Sub SubWeapon1_Leave(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubWeapon1.Leave
            If Me.SubWeapon1.Text = "" Then
                Me.SubWeapon1.Tag = Me.SubWeapon1.Text
                UpdateEquip1List()
            Else : Me.SubWeapon1.SelectAll()
            End If
            'TODO: Si le texte tapé lorsque l'utilisateur quitte la combobox n'existe pas
            'dans la liste déroulante courante (ou ne déclenche pas l'event SelectedIndexChanged),
            'alors SelectAll + afficher bulle d'erreur
        End Sub
     
        Private Sub MainWeapon1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles MainWeapon1.SelectedIndexChanged
            If IsInitialized Then
                IsInitialized = False
                Dim SubWeapon1View = New DataView(Me.DataSet.Weapon)
                SubWeapon1View.RowFilter = "NOT( Names = '" & Replace(Me.MainWeapon1.Text, "'", "''") & "' AND [Rare Tag] = 'True' ) AND ( [Equippable Jobs] LIKE '*" & Me.MainJob1.Text & "*' OR [Equippable Jobs] LIKE 'ALL' ) AND Level <= '" & Me.MainLevel1.Value & "'"
                SubWeapon1View.RowStateFilter = DataViewRowState.CurrentRows
                Me.SubWeapon1.DataSource = SubWeapon1View
                Me.SubWeapon1.DisplayMember = "Names"
                Me.MainWeapon1.Tag = Me.MainWeapon1.Text
                Me.SubWeapon1.Text = Me.SubWeapon1.Tag.ToString
                IsInitialized = True
            End If
        End Sub
     
        Private Sub SubWeapon1_SelectedIndexChanged(ByVal sender As Object, ByVal e As System.EventArgs) Handles SubWeapon1.SelectedIndexChanged
            If IsInitialized Then
                IsInitialized = False
                Dim MainWeapon1View As DataView = New DataView(Me.DataSet.Weapon)
                MainWeapon1View.RowFilter = "NOT( Names = '" & Replace(Me.SubWeapon1.Text, "'", "''") & "' AND [Rare Tag] = 'True' ) AND ( [Equippable Jobs] LIKE '*" & Me.MainJob1.Text & "*' OR [Equippable Jobs] LIKE 'ALL' ) AND Level <= '" & Me.MainLevel1.Value & "'"
                MainWeapon1View.RowStateFilter = DataViewRowState.CurrentRows
                Me.MainWeapon1.DataSource = MainWeapon1View
                Me.MainWeapon1.DisplayMember = "Names"
                Me.SubWeapon1.Tag = Me.SubWeapon1.Text
                Me.MainWeapon1.Text = Me.MainWeapon1.Tag.ToString
                IsInitialized = True
            End If
        End Sub
     
        Private Sub UpdateEquip1List()
            If IsInitialized Then
                IsInitialized = False
     
                Dim MainWeapon1View As DataView = New DataView(Me.DataSet.Weapon)
                MainWeapon1View.RowFilter = "NOT( Names = '" & Replace(Me.SubWeapon1.Text, "'", "''") & "' AND [Rare Tag] = 'True' ) AND ( [Equippable Jobs] LIKE '*" & Me.MainJob1.Text & "*' OR [Equippable Jobs] LIKE 'ALL' ) AND Level <= '" & Me.MainLevel1.Value & "'"
                MainWeapon1View.RowStateFilter = DataViewRowState.CurrentRows
                MainWeapon1View.ApplyDefaultSort = True
                Me.MainWeapon1.DataSource = MainWeapon1View
                Me.MainWeapon1.DisplayMember = "Names"
                If MainWeapon1View.Find(Me.MainWeapon1.Tag.ToString) > -1 Then
                    Me.MainWeapon1.Text = Me.MainWeapon1.Tag.ToString
                Else
                    Me.MainWeapon1.ResetText()
                    Me.MainWeapon1.Tag = ""
                End If
     
                Dim SubWeapon1View As DataView = New DataView(Me.DataSet.Weapon)
                SubWeapon1View = New DataView(Me.DataSet.Weapon)
                SubWeapon1View.RowFilter = "NOT( Names = '" & Replace(Me.MainWeapon1.Text, "'", "''") & "' AND [Rare Tag] = 'True' ) AND ( [Equippable Jobs] LIKE '*" & Me.MainJob1.Text & "*' OR [Equippable Jobs] LIKE 'ALL' ) AND Level <= '" & Me.MainLevel1.Value & "'"
                SubWeapon1View.RowStateFilter = DataViewRowState.CurrentRows
                SubWeapon1View.ApplyDefaultSort = True
                Me.SubWeapon1.DataSource = SubWeapon1View
                Me.SubWeapon1.DisplayMember = "Names"
                If SubWeapon1View.Find(Me.SubWeapon1.Tag.ToString) > -1 Then
                    Me.SubWeapon1.Text = Me.SubWeapon1.Tag.ToString
                Else
                    Me.SubWeapon1.ResetText()
                    Me.SubWeapon1.Tag = ""
                End If
     
                IsInitialized = True
            End If
        End Sub
     
    'End Class
    Ce code nécessite 4 comboboxs, nommées "MainJob1" "MainLevel1" "MainWeapon1" et "SubWeapon1".
    Les 2 premières (job & level) servent de base à toutes les comboboxs d'équipement qui suivent (ici je n'utilise que les armes dans chaque main).
    Ces 2 premières cbx initialisent les 2 autres, càd reset leurs text à "" et leurs listes déroulantes à toutes les armes equippables par le Job et level sélectionnés.
    Les 2 cbx Main & Sub Weapons ont également une exclusivité mutuelle sur leurs listes déroulantes, en fonction de la valeur tapée dans l'une ou l'autre cbx.


    La dernière chose qui reste à implémenter est:
    - si on regarde bien, beaucoup de code redondant apparait, d'autant plus que cela ne gère que 4 comboboxs, en réalité je dois faire pareil pour 30 autres comboboxs (pas toutes mutuellement exclusives heureusement), puis dupliquer tout ca pour un Setup2.

    Question : est-il possible d'obtenir les mêmes comportements avec un code simplifié ?

  6. #6
    Rédacteur/Modérateur


    Homme Profil pro
    Développeur .NET
    Inscrit en
    Février 2004
    Messages
    19 875
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Développeur .NET
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Février 2004
    Messages : 19 875
    Points : 39 749
    Points
    39 749
    Par défaut
    l'expression utilisée pour les RowFilter des dataviews lève une exception si la valeur sélectionnée contient un apostrophe (exemple ("Garuda's Dagger")
    Parce que l'apostrophe est le délimitateur de chaine dans le "mini-langage" des expressions dataset (comme en SQL d'ailleurs), donc l'apostrophe après le a est considéré comme la fin de la chaine, et la suite n'est pas comprise par le parseur. Il suffit de les doubler avec un truc du genre texte.Replace("'", "''")

  7. #7
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 140
    Points : 37
    Points
    37
    Par défaut
    Ok merci Tomlev, je ne connaissait pas cette fonction Replace.

    Code corrigé dans mon post précédent.

    La question de simplification tient toujours par contre ...

  8. #8
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 140
    Points : 37
    Points
    37
    Par défaut
    Bonjour

    J'ai trouvé un début de réponse avec la boucle suivante :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
            For Each dt As DataTable In Me.DataSet.Tables
                If dt.Columns.Contains("Names") Then
                    For Each Cbx As ComboBox In Me.TPsetsFlowLayoutPanel.Controls.OfType(Of ComboBox)()
                        If Cbx.Name.Contains(dt.TableName) Then
                            Cbx.Tag = ""
                            UpdateEquip1List(Cbx, dt, "Names")
                        End If
                    Next
                End If
            Next
    Mes 30 comboboxs étant groupées dans des FlowLayoutPanels, je fait donc une recherche des comboboxs se trouvant dans les FlowLayoutPanels concernés (3e ligne de code, en gras).
    ... et c'est là que ca coince

    Je m'explique:
    en réalité il n'ya pas 1 seul flowlayoutpanel sur mon interface, mais 8. Pour ma boucle, seuls 2 m'interessent, leurs noms étant:
    "TPsetsFlowLayoutPanel"
    et
    "WSsetsFlowLayoutPanel"

    J'essaie donc de faire un Join ou Union ou autre méthode j'en sait rien justement, de ces 2 FLPs, à la place de la portion en gras dans le code ci-dessus. A chaque tentative d'écriture, je me heurte à des erreurs de type...

    Par exemple si je tape :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    ... In Join(Me.TPsetsFlowLayoutPanel.Controls.OfType(Of ComboBox)(), Me.TPsetsFlowLayoutPanel.Controls.OfType(Of ComboBox)())
    Ca me sort l'erreur: Join() ne peut concaténer que des strings, pas des controlcollections...

    Merci de m'aider s.v.p.

  9. #9
    Membre éprouvé
    Profil pro
    Inscrit en
    Octobre 2006
    Messages
    665
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2006
    Messages : 665
    Points : 1 161
    Points
    1 161
    Par défaut
    Bonjour,
    hormis le rajout d'une boucle, je ne vois pas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
            For Each dt As DataTable In Me.dataset.Tables
                If dt.Columns.Contains("Names") Then
                    For Each flpanel As FlowLayoutPanel In New Control() {TPsetsFlowLayoutPanel, WSsetsFlowLayoutPanel}
                        For Each Cbx As ComboBox In flpanel.Controls.OfType(Of ComboBox)()
                            If Cbx.Name.Contains(dt.TableName) Then
                                MessageBox.Show(Cbx.Name)
                            End If
                        Next
                    Next
                End If
            Next
    A contrôler que le For Each flpanel ne boucle que sur les deux contrôles indiqués.

  10. #10
    Nouveau membre du Club
    Profil pro
    Inscrit en
    Août 2009
    Messages
    140
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2009
    Messages : 140
    Points : 37
    Points
    37
    Par défaut
    Bonsoir

    Merci Chris, ca marche.

    Je ne sait pas comment tu as trouvé, mais en ce qui me concerne, VB2008 n'est pas si simple à coder qu'on le croirait, malgré l'Intellisense...
    J'ai rien trouvé qui resssemble à une collection ayant TOUS les contrôles enfants d'un container de nom connu...
    J'ai le même problème dans l'autre topic avec les TableAdapters... y a des espaces de noms c bien sympa mais incompatibles dans une boucle For...

    Pour l'instant je me contenterai de ta solution, merci encore

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. [AC-2010] Formulaire multi-critères sur plusieurs tables
    Par Ohjoke dans le forum Access
    Réponses: 2
    Dernier message: 24/11/2013, 13h07
  2. Recherche multi-critères sur plusieurs tables
    Par destinynova dans le forum IHM
    Réponses: 33
    Dernier message: 25/09/2013, 22h42
  3. Réponses: 7
    Dernier message: 04/04/2007, 16h34
  4. Réponses: 6
    Dernier message: 18/03/2007, 16h22
  5. Multi critère sur plusieurs tables
    Par djpit dans le forum Access
    Réponses: 4
    Dernier message: 24/08/2006, 17h49

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo