2009-03-13 18 views
3

Ich schaue mir dieses MVVM-Zeug an und ich stehe vor einem Problem.ICommand in MVVM WPF

Die Situation ist ziemlich einfach.

Ich habe den folgenden Code in meiner index.xaml Seite

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

und in meinem index.xaml.cs

...

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

und hier ist mein 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; 
     } 
    } 
} 

schließlich

hier meine Kontrolle XAML Movieview

ist
<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> 

Also ich habe das Problem ist, dass wenn ich gesetzt Itemssource bei Bindung

es nicht alles

machen, wenn ich Itemssource = "{Binding lm}"

es auffüllt meine Items aber der Befehlssatz (Command = "{Binding Path = TestCommand}") nicht der Fall ist nicht arbeiten.

Natürlich funktioniert es nicht, da TestCommand nicht zu meinem Objekt Objekt Filme gehört.

So endlich ist meine Frage,

was muss ich Itemscontrol übergeben, um es Arbeit zu machen?

Thx im Voraus

Antwort

1

Verstanden

arbeiten hier wird die Sache

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

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

Also war die RelativeSource die Sache, die ich verpasst habe.

Wenn jemand eine gute Erklärung dazu hat, würde ich definitiv glücklich sein.

+0

Siehe Antwort von @ Arcturus: In der Elementvorlage wird Ihr DataContext in das spezifische Element geändert, das angezeigt wird. Der Befehl, an den Sie binden möchten, befindet sich im Datenkontext der übergeordneten Ansicht (Ihr Anzeigemodell), nicht im Datenkontext des Elements (eine einzelne Instanz von 'Movie'). –

+0

Auch DataContext =" {Binding} " ist redundant: Sie binden 'DataContext' an den gesamten aktuellen Datenkontext, was es bereits ist :) –

2

Versuchen Sie, die INotifyPropertyChanged-Schnittstelle implementieren:

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)); 
     } 
    }  
} 

Was passiert, ist, dass der TestCommand einen Wert hat, und die UI erhält keine Benachrichtigung, dass eine Änderung stattfindet .. Auf Kontrollen Sie lösen dieses Problem Abhängigkeitseigenschaften verwendet wird, auf Datenobjekt, können Sie die INotifyPropertyChanged Schnittstelle ..

Zweitens verwenden können, haben die Filmobjekte keinen Verweis auf das übergeordnete Objekt ..

Sie können dieses Problem auf drei verschiedene Arten lösen:

  1. eine Referenz auf das Modell auf Film haben, und die Bind-Pfad wie so machen: also .. wenn Sie Eigenschaft ist ParentMovieModel genannt, dann Die Bindung wird wie folgt aussehen:

    {Bindungspfad = ParentMovieModel.TestCommand}

  2. Machen Sie eine Bindung basierend auf ElementName wie folgt: Suchen Sie das übergeordnete Steuerelement, wo Sie Ihren DataContext festlegen, und geben Sie einen Namen: d. Erstellen Sie nun eine Bindung auf der Basis des Elementnamen wie folgt:

    {Binding Elementnamen = Root, Path = DataContext.TextCommand}

  3. ein bindendes basierte auf einer Relative etwa so: die übergeordnete Steuerung nach Art sucht nach oben, und verwenden den gleichen Weg wie die oben ...

    {Binding Relative = {Relative FindAncestor, AncestorType = {x: Typ yourparentwindowtype}}, Path = DataContext.TextCommand}

+1

Wie hilft die Implementierung der INotifyPropertyChanged-Schnittstelle in diesem Fall? Sie weisen TestCommand im Konstruktor einen Wert zu. Wie kann irgendetwas zu dem PropertyChanged-Ereignis zu diesem Zeitpunkt abonniert werden? –

0

Was <ItemsControl ItemsSource="{Binding Path=lm}"> ?

0

im Itemssource = "{Binding Path = lm}"> Fall

Itemscontrol funktioniert gut, aber ich complety meine MovieViewModel

umgehen und ich habe dies im Ausgabefenster

-System. Windows.Data Error: 39: BindingExpression path error: Eigenschaft 'TestCommand' nicht gefunden für 'object' '' Movies '(HashCode = 1031007)'. BindingExpression: Pfad = TestCommand; DataItem = 'Filme' (HashCode = 1031007); Zielelement ist 'Button' (Name = ''); Zieleigenschaft ist ‚Command‘ (Typ ‚ICommand‘)

Filme Objekt meiner Einheit ist und besitzt nur den Titel und Direktor Eigenschaften

4

Sobald Ihre Elemente gerendert werden, wird jedes Element auf den DataContext der bestimmten Zeile gesetzt, die es darstellt, so dass Sie nicht mehr auf Ihren ersten DataContext verweisen können. Auch aufgrund der Tatsache, dass Sie in sind ein Datatemplate, Ihre Bindungen anfangen zu arbeiten, wenn es für diese Vorlage muß, ist .. so in diesem Fall, dass Sie Ihre Eltern Kontrolle durch eine Bindung Relative ...

Hoffnung, dass einige Dinge erklärt suchen müssen up ..

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 
} 
}