WPF : InvalidOperationException : un ItemsControl est incohérent avec sa source items
Bonjour tout le monde,
Je suis en train de m’entrainer avec WPF, C#,EF 6 Code First . j’ai développé un petit formulaire WPF de simulation de crédit, Contenant :
- Des borders à gauche ayant des champs de saisie(à savoir le montant de crédit, le taux d’intérêts, la durée du contrat en nombre de mois etc.) ,
- Une datagrid contenant l’échéancier
Chaque changement de l’un des paramètres à gauche entraîne la mise à jour de la datagrid liée à l’échéancier.
Je passe d’un champ à l’autre à l’aide de la touche « Entrée ».
Tout ça marche très bien, sauf que lorsque je change la durée du contrat, la longueur et le contenu de la liste liée à la datagrid se mettent à jour (j’ai vérifié ça à l’aide d’un fichier de log) mais les changements ne sont pas répercutés sur la datagrid. Et lorsque je fais un scroll de la datagrid l’exception suivante est levée :
InvalidOperationException : un ItemsControl est incohérent avec sa source item
Ci-après le code :
Code:
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
|
//*********************************************************************************************************************************************
// EventHandler de keydown pour chaque champs de saisie
//*********************************************************************************************************************************************
private void txBase_KeyDown(object sender, KeyEventArgs e)
{
string fieldName = "";
TraversalRequest tRequest = null;
UIElement keyboardFocus = Keyboard.FocusedElement as UIElement;
if (sender.GetType().Name == "TextBox" || sender.GetType().Name == "NumberEditor")
fieldName = (sender as TextBox).Name;
switch (e.Key)
{
case Key.Enter :
try
{
if (fieldName == "txloy1" && _currentSimulation.FirstLoyer !=0.000)
{
_currentSimulation.echeancier[0].MontantHT = _currentSimulation.FirstLoyer;
_currentSimulation.echeancier[0].Fixe = true;
}
_currentSimulation.RefreshEcheancier();
SimulationUIBinding();
}
catch (Exception ex)
{
_currentLog.LogException(ex);
UICommon.ShowErrorMessage(ex);
}
//Movefocus(FocusNavigationDirection.Next);
tRequest = new TraversalRequest(FocusNavigationDirection.Next);
if (keyboardFocus != null)
{
keyboardFocus.MoveFocus(tRequest);
}
break;
}
e.Handled = true;
}
//*********************************************************************************************************************************************
//Méhode de databinding et affichage des totaux (située dans le window wpf)
//*********************************************************************************************************************************************
private void SimulationUIBinding()
{
try
{
masterGrid.DataContext = _currentSimulation;
gridLoyers.DataContext = _currentSimulation.echeancier;
if (_currentSimulation.echeancier.Count() > 0)
RefreshTotal();
}
catch (Exception ex)
{
UICommon.ShowErrorMessage(ex);
}
}
//*********************************************************************************************************************************************
//Méthode de calcul du loyer et dapplication des paramètres (Business logic dans l'entité simulation
//*********************************************************************************************************************************************
public void RefreshEcheancier()
{
int l = echeancier.Count();
//Ajout ou suppression d'échéances à la collection si la durée entrée est différente de la longueur actuelle de la List echeancier
if (l != DureeCtr) MaintenirEcheancier();
if (Montant != 0.000)
{
double loyer = AnnuityCompute();
echeancier.Where(e => e.Fixe == false).All(e =>
{
e.MontantHT = loyer;
return true;
});
}
//Met à jour les différents champs calculables
UpdateCollectionEcheances();
}
//*********************************************************************************************************************************************
// Cette méthode permet d'ajouter ou de supprimer des échéances selon la durée et la longueur de l'échéancier
//**********************************************************************************************************************************************
private void MaintenirEcheancier()
{
int listLenght = echeancier.Count();
int nbloy = listLenght - DureeCtr;
if (echeancier == null || listLenght == 0)
CreateEmptyEcheancier();
else
{
if (nbloy != 0)
{
if (nbloy > 0)
echeancier.ToList().RemoveRange(DureeCtr, nbloy);
else
{
for (Byte i=1; i<= Math.Abs(nbloy); i++)
echeancier.Add(new Echeance(((Byte)(listLenght+i))));
}
}
}
} |
WPF : InvalidOperationException : un ItemsControl est incohérent avec sa source items Enfin Résolue
Bonjour tout le monde,
Le problème c'est que la liste "echeancier" n'est pas en train de notifier le UI de ses changements. C'est pour cela qu'à chaque changement de sa longueur, une exception est levée vue l'incohérence entre la longueur réelle de la liste et celle affichée dans l'UI (datagrid). Utiliser Une ObservableCollection à la place d'une liste résout le problème, mais reste à nettoyer les entités de mon domaine de tout ce qui est lié à l'UI afin d'assurer une bonne séparation des couches. Je vais utiliser pour ça le patron MVVM afin de migrer les entités vers la couche model et supprimant toute héritage de INotifyPropertyChanged (à la charge de la couche ViewModel). Voici un lien intéressant pour ceux qui s'intéressent :
http://japf.developpez.com/tutoriels...-et-testables/
Merci à tous.