2010-01-11 6 views
1

Je crée une application WPF en utilisant le modèle de conception MVVM, et j'essaye de créer une Combobox qui permet à l'utilisateur de modifier les éléments dans la liste déroulante à runtime, similaire à la façon dont MS Access 2007 vous permet de le faire. J'ai donc créé un UserControl qui se construit au-dessus d'une Combobox ... lorsque la liste déroulante est affichée, il y a un bouton sous la liste qui ouvre une autre fenêtre pour éditer les éléments de la liste. Assez simple, mais la fenêtre contextuelle ne sait rien sur le type d'éléments dans la liste, à part qu'ils sont d'un type ObservableCollection.Ajout d'un élément à un ObservableCollection d'un type inconnu

Vous pouvez voir une capture d'écran de ce que j'essaie d'expliquer HERE.

Par exemple, dans la vue, je lie la liste déroulante personnalisée à ObservableCollection<Sizes>. Je clique sur le bouton pour éditer la liste et la fenêtre popup affiche tous les éléments dans un TextBox pour que l'utilisateur édite. Le problème est d'essayer d'ajouter/mettre à jour/supprimer des éléments dans ObservableCollection à partir de la fenêtre contextuelle. Cette fenêtre ne sait rien sur ObservableCollection, autre que le nom du champ d'affichage (this.DisplayMemberPath). Je sais que je pourrais toujours lier la combobox à un ObservableCollection<string>, ou IEnumerable<string>, mais j'utilise LINQ to SQL pour remplir les éléments de la liste déroulante, et je dois être conscient du suivi des changements sur tous mes objets afin que je puisse mettre à jour la base de données des modifications apportées à la liste. Par conséquent, (je pense) je dois utiliser ObservableCollection<Sizes> afin de surveiller le suivi des changements. J'ai aussi joué avec l'idée d'utiliser l'événement CollectionChanged pour mettre à jour la base de données, mais je me demande s'il existe une méthode plus propre.

J'ai le sentiment que je vais avoir besoin d'utiliser Reflection pour mettre à jour la liste, mais je ne suis pas très versé dans l'utilisation de Reflection.

Voici mon code source pour afficher la fenêtre:

public event EventHandler<EventArgs> EditListClick; 
private void EditButton_Click(object sender, RoutedEventArgs e) 
{ 
    if (this.EditListDialog == null) 
    { 
     // Create the default dialog window for editing the list 
     EditListDialogWindow dialog = new EditListDialogWindow(); 
     string items = string.Empty; 

     if (this.Items != null) 
     { 
      // Loop through each item and flatten the list 
      foreach (object item in this.Items) 
      { 
       PropertyInfo pi = item.GetType().GetProperty(this.DisplayMemberPath); 
       string value = pi.GetValue(item, null) as string; 

       items = string.Concat(items, ((items == string.Empty) ? items : "\n") + value); 
      } 

      // Now pass the information to the dialog window 
      dialog.TextList = items; 
     } 

     // Set the owner and display the dialog 
     dialog.Owner = Window.GetWindow(this); 
     dialog.ShowDialog(); 

     // If the user has pressed the OK button... 
     if (dialog.DialogResult.HasValue && dialog.DialogResult.Value) 
     { 
      // Make sure there has been a change 
      if (items != dialog.TextList) 
      { 
       // Unflatten the string into an Array 
       string[] itemArray = dialog.TextList.Split(new string[]{"\n", "\r"}, StringSplitOptions.RemoveEmptyEntries); 

       // Add the items to the list 
       foreach (string item in itemArray) 
       { 
        // This is where I run into problems... 
        // Should I be using reflection here?? 
        ((ObservableCollection<object>)this.ItemsSource).Add(item.Trim()); 
       } 
      } 
     } 
    } 

    if (EditListClick != null) 
     EditListClick(this, EventArgs.Empty); 
} 

Répondre

0

Avez-vous essayé d'utiliser un IValueConverter?

Lorsque vous liez ObservbleCollection à la zone de liste déroulante personnalisée, définissez un IValueConverter personnalisé. T His définit 2 méthodes, Convert et ConvertBack. L'idée est, que vous pouvez convertir les types.

Dans ce cas, vous pouvez avoir votre ObservableCollection<Sizes> et le convertisseur de liaison le prendra et le convertira au type requis.

Si vous définissez le convertisseur sur la liaison de collecte, vous pouvez convertir vers et depuis ObservableCollection<Sizes> et ObservableCollection<string>.

L'autre option est de définir le IValueConverter en interne pour le ComboBox personnalisé et de faire la conversion de Sizes à string. Une autre option, en conjonction est de spécifier un itemtemplate contenant la liaison et la conversion.

HtH.

+0

Hmm ...Je n'avais pas pensé à utiliser un ValueConverter de cette façon avant ... Je vais essayer et revenir avec vous. Merci! – Brent

+0

Le seul problème que j'ai avec cela est que cela m'obligerait à écrire un tas de ValueConverters pour chaque type de combobox que j'utilise, car chacun contiendrait un type différent. Ce sera une grande application, donc je pourrais avoir 30-50 différents types de listes. Je pense vraiment que la réflexion est la voie à suivre, mais je ne sais pas comment l'implémenter ... – Brent

+0

Hmmm, ça change certainement. Chacun de ces objets dans les listes sera-t-il personnalisé? –

2

Il semble que vous ayez besoin de connaître la liste, mais pas les types spécifiques. C'est là qu'interviennent les interfaces non génériques; essayez d'accéder à la liste comme IList (qui a tous les indexeur/Ajouter/Supprimer etc.), INotifyCollectionChanged (pour les notifications), etc.

Dans le cas plus général, il est également IBindingList/IBindingListView/ITypedList etc, mais je n » Je pense que vous en aurez besoin dans ce cas.

+0

Je ne suis pas sûr de comprendre comment implémenter ceci. Pourriez-vous fournir un exemple de code? – Brent

Questions connexes