2010-11-04 13 views
1

j'ai une application de test de motif MVVM qui secouait beaucoup deWPF - viewmodel - erreurs contraignantes, alors que le rafraîchissement des données

System.Windows.Data Error: 17 : Cannot get 'Item[]' value (type 'ChuteGroup') from 'Groups' (type 'ChuteGroupsModel'). BindingExpression:Path=Groups[0]; DataItem='MainViewModel' (HashCode=41802290); target element is 'ChuteView' (Name=''); target property is 'DataContext' (type 'Object') ArgumentOutOfRangeException:'System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: index' 

Cela arrive quand je rentre ma routine « OnRefresh » dans le viewmodel. J'ai une collection observable appelée "Current" et la première chose que je fais dans la routine d'actualisation est d'effacer les entrées de la collection Current. Je reçois alors un tas de ces messages d'erreur de données 17 parce que je pense en arrière-plan les liaisons essayent de mettre à jour et maintenant il n'y a rien dans la collection jusqu'à ce que je remplisse et recrée chaque entrée dans la collection observable.

Y a-t-il une meilleure façon de procéder? Les performances d'exécution ne semblent pas affectées par cela, mais je n'aime pas les erreurs dans ma fenêtre de sortie. J'ai découvert que si je n'avais pas effacé la collection, sa taille a doublé à chaque fois que le viewmodel s'est rafraîchi. Étant donné que cette collection est utilisée avec 54 éléments d'interface utilisateur, qui sont liés par index, la collection ne peut pas doubler de taille ou tout ne pointera pas vers l'élément d'interface utilisateur correct.

private void FetchData() 
    { 
     ChuteGroupsModel.isDuringRefresh = true; 
     DataSet sqldata = new DataSet(); 
     SqlConnection conn = new SqlConnection("Data Source=(local);Initial Catalog=ScratchPaper;User ID=somecacct;Password=somepassword;Connect Timeout=5"); 
     SqlCommand cmd = new SqlCommand("Select chuteGroup, chuteGroupDef, TotalChutes, UpPackWave, UpColorId, UpPackWaveTS, DownPackWave, DownColorId, DownPackWaveTS from ChuteGroups Order by chuteGroup asc",conn); 
     SqlDataAdapter da = new SqlDataAdapter(cmd); 
     try 
     { 
     da.Fill(sqldata); 

     } 
     catch (Exception Ex){ MessageBox.Show(Ex.ToString());} 


     //DataSet sqldata = this.DataLayer.getDataSet("Select * from AvailableColors Order by ID asc", CommandType.Text, null); 
     foreach (DataRow row in sqldata.Tables[0].Rows) 
     { 
      ChuteGroup group = new ChuteGroup((int)row.ItemArray[0], (string)row.ItemArray[1], (int)row.ItemArray[2], (string)row.ItemArray[3],(string)row.ItemArray[4], (DateTime)row.ItemArray[5], (string)row.ItemArray[6], (string)row.ItemArray[7], (DateTime)row.ItemArray[8]); 
      Add(group); 
     } 
     ChuteGroupsModel.isDuringRefresh = false; 
    } 

private void onRefresh(object sender, System.EventArgs e) 
    { 
     try 
     {  
      if (ChuteGroupsModel.isDuringRefresh) 
      { 
       return; 
      } 
      Refresh(); 
     } 
     catch (Exception ex) 
     { 
      System.Diagnostics.Debug.WriteLine(ex.Message.ToString()); 
     } 
    } 
public void Refresh() 
    { 
     Current.Clear(); //Current is a static reference to my collection 
     FetchData(); 
    } 

Répondre

1

Vous avez raison de supposer que les erreurs de liaison sont dues à l'effacement de votre collection. Comme vous ne subissez aucune pénalité de performance, je ne m'inquiéterais pas trop.

Si vous êtes vraiment ennuyé par eux, vous pouvez créer un nouveau type de collection observable pour vous permettre de définir les nouvelles valeurs. Si vous craquez ouvrir la classe ObservableCollection dans le réflecteur, vous souhaitez copier la mise en œuvre, et d'ajouter une nouvelle méthode comme ceci:

public class ObservableList<T> : Collection<T>, INotifyCollectionChanged, INotifyPropertyChanged 
{ 
    // ObservableCollection implementation here 
    ... 

    public void SetItems(IEnumerable<T> items) 
    { 
     this.CheckReentrancy(); 
     base.ClearItems(); 

     int i = 0; 
     foreach (var item in items) 
     { 
      base.InsertItem(i, item); 
      ++i; 
     } 

     this.OnPropertyChanged("Count"); 
     this.OnPropertyChanged("Item[]"); 
     this.OnCollectionReset(); 

    } 
} 

Ensuite, au lieu d'effacer vos données et ajouter une ligne à la fois, vous d appelez la méthode SetItems.

+0

Je dois vraiment en apprendre davantage sur le réflecteur. Cela semble avoir de bonnes chances de faire ce dont j'ai besoin. Merci pour votre contribution Abe! – TWood

0

Je sais que cela fait un moment que cette question a été posée, mais une méthode qui a résolu ce type de problème pour moi est d'utiliser RemoveAt (0) (et/ou les emplacements que vous avez besoin) et ensuite ajouter vos données à la collection. Il semble y avoir une sorte de problème de synchronisation avec Clear() en ce que pour quelques instants brefs, les appels des liaisons pour les données retourne une collection vide, donc les messages de sortie. Cela peut sembler un peu détaillé et peut-être brutal par rapport à un clair plus générique, mais il supprime les erreurs et améliore sensiblement les performances.