2010-07-23 6 views
2

J'expérimente MVVM et je n'arrive pas à m'en rendre compte.Recommandez la meilleure approche dans cette situation

J'ai une vue (windows) qui a plusieurs contrôles répétés.

Disons que j'ai 4 paires de boutons de texte. Leur comportement devrait être le même, après avoir appuyé sur un bouton apparié zone de texte dit "Bonjour tout le monde!"

J'ai essayé plusieurs options que je pouvais penser:

  1. un ViewModel, 4 propriétés de chaîne binded à textboxes, 1 commande
    • Quand je lie chaque bouton à la même commande je ne peux pas Indique quelle propriété doit être définie.
    • La transmission d'une commande à CommandParameter est gênante.
  2. Un ViewModel et UserControl qui héberge une zone de texte et un bouton répété 4 fois.
    • Maintenant, j'ai besoin d'exposer toutes les propriétés comme Command, CommandParameter, Text, etc .. On dirait que beaucoup de travail.
    • Impossible de dire quelle propriété doit être mise à jour après un clic.
  3. Chaque UserControl a une ViewModel
    • Cela résout en cliquant le bouton et réglage de la propriété, mais maintenant je n'ai pas la moindre idée comment extraire des textes de ViewModels imbriqués dans la fenêtre ViewModel.

est-il un autre moyen? Je pense que DataTemplates pourrait être utile, mais je ne sais pas comment.

Répondre

2

Ce que vous décrivez est une idée tellement abstraite et artificielle que cela ne justifie pas MVVM. Vous parlez de TextBox es et Buttons, qui sont tous 'View', et non pas la façon de penser MVVM. Vous commenceriez presque toujours avec un modèle.

Il n'y a pas de "modèle" en soi ici; votre spécification est littéralement pour définir la valeur d'un TextBox sur un clic Button. La liste apparemment aléatoire de «4» articles (choisis de nulle part) et un TextBox apparemment inutile ne signifie rien.

Cela mis à part et en supposant que vous avez un ensemble de 4 entités commerciales, chacune avec un champ sur eux qui est modifiable utilisateur, et une action que l'utilisateur peut déclencher, vous feriez ceci:

  • Créer une classe ViewModel pour représenter un élément - par exemple MyItemModel
  • Créer une classe ViewModel pour représenter l'ensemble des éléments (il est probable que renvoyer une collection de la première) - par exemple AllMyItemsListModel

Alors, pour la Afficher:

  • Créer un ItemsControl, avec ItemsSource lié à une instance de la « collection » de la deuxième classe ViewModel
  • Pour chaque ItemTemplate, un modèle ou UserControl pour chaque élément
  • Dans le modèle ou UserControl, lier la propriété Text de TextBox à la propriété appropriée de la première classe
  • Lier la propriété de Button à une propriété de première classe en renvoyant un ICommand - en utilisant RelayCommand par exemple

Je ne sais pas ce que vous entendez par « extraire des textes de ViewModels imbriqués à la fenêtre ViewModel » - qu'est-ce que cela signifie et pourquoi voudriez-vous faire?

Espérons que ça aide.

+0

+1 pour la réponse bien présentée. Mais je ne pense pas que l'affirmation de créer une classe ViewModel pour représenter un élément de modèle est vraie. Au lieu de cela, la classe ViewModel est créée en fonction de la vue et de la vue uniquement. Si la vue requiert des données de modèle, la propriété particulière dans le modèle est utilisée par ViewModel pour répondre aux besoins de la vue. Ainsi, le premier ViewModel pourrait contenir le texte de la zone de texte (à partir de Model si nécessaire) et l'Icommand et le second pourrait contenir le 'Collection ' – Amsakanna

+0

Merci pour le commentaire, mais je suggérais que vous ne démarreriez jamais l'application * (pas le ViewModel) avec une vue; vous n'écririez jamais une application 'pour mettre du texte dans des boîtes', vous l'écririez pour un but réel avec des entités réelles. Donc, vous avez besoin d'un modèle pour commencer. Je crois que ma réponse dit déjà que la première classe contiendrait une propriété pour le texte et une commande, et la seconde serait aussi une collection. –

+0

Vous avez raison, j'ai eu la mauvaise approche ici. Je le vois maintenant. Mais je suis d'accord que ViewModels doit être créé en fonction de la vue et non du modèle. Quoi qu'il en soit dans mon cas je n'ai pas de collection c'est un nombre fixe de contrôles répétés qui devraient représenter un nombre fixe de chaînes dans mon modèle. – Kugel

1

Numéro 3. Sauf qu'il y aurait juste un UserControl avec viewmodel et ensuite la page principale qui aurait plusieurs instances de ce UserControl dessus. Si la fenêtre principale a besoin d'informations provenant du UserControl, vous pouvez le passer à travers des événements ou utiliser quelque chose comme MVVM Light et sa classe messenger.

1

Il n'est pas nécessaire de créer un ViewModel séparé pour un contrôle réutilisable ayant un comportement aussi simple. Juste en ajoutant un peu de DependencyProperties et un gestionnaire d'événements à UserControl simple, vous pouvez réutiliser la logique et ne définir que les propriétés qui sont réellement différentes sur chaque instance. Pour le XAML UserControl, il vous suffit de connecter le TextBox au DependencyProperty et le gestionnaire Button to a Click.

<DockPanel> 
    <Button Content="Reset" Click="Button_Click"/> 
    <TextBox Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type UserControl}}, Path=Text}"/> 
</DockPanel> 

Le code pour le UserControl a juste besoin de définir les propriétés qui peuvent être liés à l'extérieur et le gestionnaire pour réinitialiser le texte.

public partial class ResetTextBox : UserControl 
{ 
    public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
     "Text", 
     typeof(string), 
     typeof(ResetTextBox), 
     new FrameworkPropertyMetadata(null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault)); 

    public string Text 
    { 
     get { return (string)GetValue(TextProperty); } 
     set { SetValue(TextProperty, value); } 
    } 

    public static readonly DependencyProperty ResetTextProperty = DependencyProperty.Register(
     "ResetText", 
     typeof(string), 
     typeof(ResetTextBox), 
     new UIPropertyMetadata(String.Empty)); 

    public string ResetText 
    { 
     get { return (string)GetValue(ResetTextProperty); } 
     set { SetValue(ResetTextProperty, value); } 
    } 

    public ResetTextBox() 
    { 
     InitializeComponent(); 
    } 

    private void Button_Click(object sender, RoutedEventArgs e) 
    { 
     Text = ResetText; 
    } 
} 

ensuite d'utiliser la commande que vous avez juste besoin de se lier à vos propriétés de chaîne ViewModel et définissez le texte par défaut qui doit être appliqué sur une remise à zéro qui peut soit être codé en dur ici, ou lié à d'autres propriétés VM.

<StackPanel> 
    <local:ResetTextBox ResetText="One" Text="{Binding Name1}"/> 
    <local:ResetTextBox ResetText="Two" Text="{Binding Name2}"/> 
    <local:ResetTextBox ResetText="Three" Text="{Binding Name3}"/> 
</StackPanel> 
+0

Ceci est mon appreach # 2. Dans votre cas, vous avez seulement deux propriétés exposées. Dans mon cas, j'ai eu 4 ou 5 et cela semble beaucoup de travail, juste exposer les propriétés. – Kugel

+0

Ce n'est pas ce que vous avez décrit dans # 2. Votre approche nécessitait des propriétés supplémentaires car vous utilisiez ViewModel pour effectuer le travail que l'UserControl est en train de faire ici. Si vous utilisez cette méthode, vous n'avez pas de propriétés supplémentaires pour toutes les fonctions de commande car au lieu d'agir via une commande transmise à partir de votre ViewModel, tout cela est géré en interne par UserControl. –

+0

Vous avez raison. J'aime ta réponse, parce que c'est pratique. Mais ce n'est pas testable. Mais je suppose que ça va pour les petits UserControls. – Kugel

Questions connexes