2009-03-13 4 views
3

Я смотрю на этот материал MVVM, и я столкнулся с проблемой.ICommand в MVVM WPF

Ситуация довольно проста.

У меня есть следующий код в моем index.xaml странице

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

и в моем index.xaml.cs

...

InitializeComponent(); base.DataContext = новый MovieViewModel (ent.Movies.ToList()); ....

и вот мой 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; 
     } 
    } 
} 

наконец

вот мой контроль 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> 

Так проблема у меня в том, что если я устанавливаю ItemsSource при привязке

это не делает ничего

если я устанавливаю ItemsSource = "{Binding} лм"

заселяет мой ItemsControl но команда (Command = "{Binding Path = TestCommand}") не не работа.

Конечно, это не сработает, потому что TestCommand не принадлежит моему объекту Object Movies.

Итак, наконец, мой вопрос,

, что мне нужно сделать, чтобы перейти к ItemsControl, чтобы сделать его работу?

Thx заранее

ответ

1

Понял работает

здесь вещь

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

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

, поэтому RelativeSource - это то, что я пропустил.

Если у кого-то есть хорошее объяснение этого, я был бы определенно счастлив.

+0

См. Ответ @ Arcturus: в шаблоне элемента ваш DataContext изменяется на конкретный отображаемый элемент. Команда, которую вы хотите связать, находится в контексте данных родительского представления (ваша модель представления), а не контексте данных элемента (который является единственным экземпляром 'Movie') –

+0

Кроме того, DataContext =" {Binding} " redundant: вы привязываете 'DataContext' ко всему текущему контексту данных, который он уже есть :) –

2

Попробуйте реализовать интерфейс 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)); 
     } 
    }  
} 

Что происходит, что TestCommand имеет значение, а пользовательский интерфейс не получает никаких уведомлений о том, что изменение происходящее .. На контролях вы решаете эту проблему, используя свойства Dependency, на объекте данных, вы можете использовать интерфейс INotifyPropertyChanged.

Во-вторых, объекты Movie не имеют ссылки на родительский объект.

Вы можете решить эту проблему тремя различными способами:

  1. имеют обратную ссылку модели на кино, и сделать Bind путь следующим образом: то есть .. если свойство называется ParentMovieModel, то ваш Связывание будет выглядеть так:

    {Binding Path = ParentMovieModel.TestCommand}

  2. Сделайте привязку на основе ElementName следующим образом: найдите родительский элемент управления, на который вы установили свой DataContext, и укажите ему имя: i.e Root. Теперь создайте привязку на основе ElementName как так:

    {Binding ElementName = корень, Path = DataContext.TextCommand}

  3. сделать привязку на основе RelativeSource как так: Ищи вверх родительский контроль по типу, и использовать тот же путь, что и выше одного ...

    {Binding RelativeSource = {RelativeSource FindAncestor, AncestorType = {х: Тип yourparentwindowtype}}, Path = DataContext.TextCommand}

+1

Как реализовать интерфейс INotifyPropertyChanged в этом случае? Вы назначаете значение TestCommand в конструкторе. Как можно подписаться на событие PropertyChanged в это время? –

0

насчет <ItemsControl ItemsSource="{Binding Path=lm}"> ?

0

в ItemsSource = "{Binding Path = лм}"> Дело

ItemsControl работает хорошо, но я complety обойти мой MovieViewModel

, и я получил это в выходном окне

системы. Ошибка Windows.Data: 39: Ошибка пути BindingExpression: свойство TestCommand не найдено в 'object' '' Movies '(HashCode = 1031007)'. BindingExpression: Path = TestCommand; DataItem = 'Фильмы' (HashCode = 1031007); целевым элементом является «Button» (Name = ''); предназначаться свойством является «Command» (типа «ICommand»)

Фильмов моего объекта лица и имеют только название и свойство директора

4

Как только ваши объекты визуализируются, каждый элемент получает значение в DataContext определенной строки, которую он представляет, поэтому вы больше не можете ссылаться на свой первый DataContext .. Также из-за того, что вы находитесь в DataTemplate, крепления начнут работать, когда есть необходимость в этом шаблон .. поэтому в этом случае вам нужно будет искать свой родительский контроль через RelativeSource связывание ...

Надежда, что объясняет некоторые вещи ..

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 
} 
} 
Смежные вопросы