ICommand в MVVM WPF

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

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

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

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

и в моем index.xaml.cs

...

InitializeComponent (); base.DataContext = new 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 в Binding

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

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

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

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

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

что мне нужно передать ItemsControl, чтобы он работал?

Спасибо заранее

6 ответов

Решение

Получил это работает

вот вещь

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

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

поэтому RelativeSource был тем, что я пропустил.

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

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

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

Попробуйте реализовать интерфейс 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 имеет значение, а пользовательский интерфейс не получает уведомлений о том, что происходит изменение. На элементах управления вы решаете эту проблему с помощью свойств зависимости, для объекта данных вы можете использовать интерфейс INotifyPropertyChanged.

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

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

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

    {Binding Path = ParentMovieModel.TestCommand}

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

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

  3. Создайте привязку на основе RelativeSource следующим образом: найдите родительский элемент управления по типу и используйте тот же путь, что и выше...

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

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

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

В случае ItemsSource="{Binding Path=lm}">

itemsControl работает хорошо, но я полностью игнорирую свою MovieViewModel

и я получил это в окне вывода

Ошибка System.Windows.Data: 39: Ошибка пути BindingExpression: свойство "TestCommand" не найдено для объекта "Фильмы" (HashCode=1031007) ". BindingExpression:Path=TestCommand; DataItem='Фильмы' (HashCode=1031007); Целевым элементом является "Кнопка" (Имя =''); Свойство target - "Command" (тип "ICommand")

Фильмы - это объект моей сущности, которому принадлежат только свойства "Название" и "Директор"

Другие вопросы по тегам