2009-03-13 5 views
3

Je regarde ce logiciel MVVM et je suis confronté à un problème.ICommand dans MVVM WPF

La situation est plutôt simple.

Je le code suivant dans ma page index.xaml

<Grid> 
    <ItemsControl ItemsSource="{Binding}"> 
     <ItemsControl.ItemTemplate> 
      <DataTemplate> 
       <view:MovieView ></view:MovieView> 
      </DataTemplate> 
     </ItemsControl.ItemTemplate> 
    </ItemsControl> 
</Grid> 

et dans mes index.xaml.cs

...

InitializeComponent(); base.DataContext = nouveau MovieViewModel (ent.Movies.ToList()); ....

et voici mon MoveViewModel

public class MovieViewModel 
{ 
    readonly List<Movies> _m; 
    public ICommand TestCommand { get; set; } 
    public MovieViewModel(List<Movies> m) 
    { 
     this.TestCommand = new TestCommand(this); 
     _m = m; 
    } 
    public List<Movies> lm 
    { 
     get 
     { 
      return _m; 
     } 
    } 
} 

enfin

ici est mon contrôle XAML MovieView

<Grid> 
    <Grid.RowDefinitions> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="Auto" /> 
     <RowDefinition Height="Auto" /> 
    </Grid.RowDefinitions> 
    <Grid.ColumnDefinitions> 
     <ColumnDefinition Width="Auto"></ColumnDefinition> 
     <ColumnDefinition Width="Auto"></ColumnDefinition> 
    </Grid.ColumnDefinitions> 
    <Label VerticalAlignment="Center" Grid.Row="0" Grid.Column="0">Title :</Label><TextBlock VerticalAlignment="Center" Grid.Row="0" Grid.Column="1" Text="{Binding Title}"></TextBlock> 
    <Label VerticalAlignment="Center" Grid.Row="1" Grid.Column="0">Director :</Label><TextBlock VerticalAlignment="Center" Grid.Row="1" Grid.Column="1" Text="{Binding Director}"></TextBlock> 
    <Button Grid.Row="2" Height="20" Command="{Binding Path=TestCommand}" Content="Edit" Margin="0,4,5,4" VerticalAlignment="Stretch" FontSize="10"/> 
</Grid> 

Le problème que j'ai est que si je mets ItemsSource à la reliure

il ne fait rien

si je mets ItemsSource = "{Binding lm}"

il Remplit mon ItemsControl mais la commande (Commande = "{Binding Path = TestCommand}") ne ne fonctionne pas.

Bien sûr, cela ne fonctionne pas car TestCommand n'appartient pas à mon objet d'entité Movies.

Donc finalement ma question est,

que dois-je passer à ItemsControl pour faire fonctionner?

Thx à l'avance

Répondre

1

obtenu ce travail

ici est la chose

<ItemsControl DataContext="{Binding}" ItemsSource="{Binding lm}"> 

Command="{Binding Path=DataContext.TestCommand, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}" 

donc le RelativeSource était la chose que j'ai manquée.

Si quelqu'un a une bonne explication de cela, je serais certainement heureux.

+0

Voir la réponse d'Arcturus: dans le modèle d'élément, votre DataContext est remplacé par l'élément spécifique affiché. La commande que vous voulez lier est sur le contexte de données de la vue parent (votre modèle de vue), pas le contexte de données de l'élément (qui est une instance unique de 'Movie') –

+0

En outre, DataContext =" {Binding} " est reduntant: vous liez 'DataContext' à l'ensemble du contexte de données actuel, ce qui est déjà le cas :) –

2

Essayez implémentant l'interface INotifyPropertyChanged:

public class MovieViewModel : INotifyPropertyChanged 
{ 
    readonly List<Movies> _m; 
    private ICommand _testCommand = null; 
    public ICommand TestCommand { get { return _testCommand; } set { _testCommand = value; NotifyPropertyChanged("TestCommand"); } } 
    public MovieViewModel(List<Movies> m) 
    { 
     this.TestCommand = new TestCommand(this); 
     _m = m;   
    } 
    public List<Movies> lm 
    { 
     get 
     { 
      return _m; 
     } 
    } 


    public event PropertyChangedEventHandler PropertyChanged; 

    protected void NotifyPropertyChanged(string sProp) 
    { 
     if (PropertyChanged != null) 
     { 
      PropertyChanged(this, new PropertyChangedEventArgs(sProp)); 
     } 
    }  
} 

Ce qui se passe est que le TestCommand a une valeur, et l'interface utilisateur ne reçoit pas de notification qu'un changement aura lieu .. Sur les contrôles vous résolvez ce problème en utilisant les propriétés de dépendance, sur l'objet de données, vous pouvez utiliser l'interface INotifyPropertyChanged.

Deuxièmement, les objets Movie ne font pas référence à l'objet parent.

Vous pouvez résoudre ce problème de trois façons différentes:

  1. ont une référence à modèle sur film, et faire le chemin Bind comme ceci: à savoir .. si vous la propriété est nommé ParentMovieModel, votre La liaison sera la suivante:

    {Binding Path = ParentMovieModel.TestCommand}

  2. Effectuez une liaison basée sur ElementName comme suit: Recherchez le contrôle parent sur lequel vous définissez votre DataContext et attribuez-lui un nom: par exemple Root. Maintenant, créez une fixation sur la base ElementName comme ceci:

    {Reliure ElementName = Root, Path = DataContext.TextCommand}

  3. Faire une fixation sur une base RelativeSource comme ceci: Cherchez le contrôle parent par type, et utiliser le même chemin que celui ci-dessus ...

    {Reliure RelativeSource = {RelativeSource FindAncestor, AncestorType = {x: type yourparentwindowtype}}, Path = DataContext.TextCommand}

+1

Comment l'implémentation de l'interface INotifyPropertyChanged aide-t-elle dans ce cas? Vous affectez une valeur à TestCommand dans le constructeur. Comment tout ce qui peut être souscrit à l'événement PropertyChanged à ce moment-là? –

0

Qu'en est-<ItemsControl ItemsSource="{Binding Path=lm}"> ?

0

dans le ItemsSource = "{Binding Path = lm}"> cas

ItemsControl fonctionne bien mais je complety court-circuiter mon MovieViewModel

et je me suis ceci dans la fenêtre de sortie

système. Erreur Windows.Data Erreur 39: BindingExpression path: propriété 'TestCommand' introuvable sur 'objet' 'Movies' (HashCode = 1031007) '. BindingExpression: Path = TestCommand; DataItem = 'Movies' (HashCode = 1031007); l'élément cible est 'Button' (Name = ''); cible propriété est 'Command' (type 'ICommand')

Movies est mon objet entité et ne possède que le titre et les propriétés Directeur

4

Dès que vos éléments sont rendus, chaque élément est défini sur le DataContext de la ligne spécifique qu'il représente, de sorte que vous ne pouvez plus faire référence à votre premier DataContext. En outre, en raison du fait que vous êtes en DataTemplate, vos fixations va commencer à travailler quand il est nécessaire pour ce modèle .. donc, dans ce cas, vous devez rechercher votre contrôle parent par une liaison de RelativeSource ...

espoir qui explique certaines choses ..

1
//include namespace 
using Microsoft.Practices.Composite.Wpf.Commands; 

readonly List<Movies> _m; 
    public ICommand TestCommand { get; set; } 
    public MovieViewModel(List<Movies> m) 
    { 
     this.TestCommand = new DelegateCommand<object>(TestcommandHandler); 
     _m = m; 
    } 
    public List<Movies> lm 
    { 
     get 
     { 
      return _m; 
     } 
    } 

void TestcommandHandler(object obj) 
{ 
     // add your logic here 
} 
} 
Questions connexes