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

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    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
    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
    Membre confirmé
    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
    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 : 44
    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
    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

+ 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