0

Привет всем. Хотел бы узнать 2 момента по поводу MVVM + WPF. Первый момент легкий, хотел бы узнать, как передать в команду параметр, при срабатывании, на самого себя, через XAML. У меня есть такой код:

<ItemsControl ItemsSource="{Binding CurrentProducts}">
...
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <Button Command="{Binding RequestCalculatorPriceProduct}" CommandParameter="{?????}"/>
        </DataTemplate>
    </ItemsControl.Template>
...
</ItemsControl>

Соответственно CurrentProducts - является коллекцией объектов IEnumerable<ProductViewModel>. У каждый ProductViewModel выглядит так:

public class ProductViewModel : BaseViewModel
{
    public Int64    Id { get; set; }
    public string   Name { get; set; }
    public string   Foto { get; set; }

    public ICommand RequestCalculatorPriceProduct { get; }

    public ProductViewModel( Int64 id, string name, string foto )
    {
        Id = id;
        Name = name;
        Foto = foto;

        RequestCalculatorPriceProduct   =   new RelayCommand<ProductViewModel>( OnCalculatorPriceProductRequest );
    }

    private void OnCalculatorPriceProductRequest( ProductViewModel currentProduct )
    {
        ...
    }
}

Мне нужно в обработчике OnCalculatorPriceProductRequest в параметре принимать ссылку на самого себя.

Итак, из вышесказанного уже видно что подход не достаточно верный, поэтому я сразу задаю вопрос на второй момент, который очень тесно связан с предыдущим: Коллекция IEnumerable<ProductViewModel> CurrentProducts у меня лежит во ViewModel страницы. Так вот, мне на самом деле бы хотелось, чтобы команда, которая сейчас в ProductViewModel была именно в ViewModel страницы, и при срабатывании команды, обработчик в параметре имел тот объект ProductViewModel, по которому щелкнули.

Как бы я не старался это сделать, у меня не получается. Вот примерный код ViewModel страницы:

public class MainPageViewModel : BasePageViewModel
{
    ...
    public IEnumerable<ProductViewModel> CurrentProducts
    {
        get { ... }
        set { ... }
    }
    public ICommand RequestCalculatorPriceProduct { get; }
    ...
    public MainPageViewModel()
    {
        RequestCalculatorPriceProduct = new RelayCommand<ProductViewModel>( OnCalculatorPriceProductRequest );
        ...
    }
    private void OnCalculatorPriceProductRequest( ProductViewModel currentProduct )
    {
        // Я хочу вот тут получать выбранный ProductViewModel
    }
    ...     
}

Но с той разметкой XAML, которую я показал выше, это не работает. Команда вообще не срабатывает. Подскажите в чем может быть проблема? И как реализовать следующие моменты, которые я описал

Rasul
  • 1,101
  • 7
  • 14
Bretbas
  • 402
  • CommandParameter="{Binding}" – Андрей NOP Nov 27 '17 at 17:16
  • А почему вы в OnCalculatorPriceProductRequest не можете просто использовать this? Зачем вам этот параметр вообще? – VladD Nov 27 '17 at 17:16
  • По поводу второго вопроса вам нужно воспользоваться RelativeSource, примерно как здесь: https://ru.stackoverflow.com/a/746587/218063 – Андрей NOP Nov 27 '17 at 17:21
  • 1
    @VladD, автору команда нужна в MainVm, но он не знает как правильно привязаться, я так понимаю – Андрей NOP Nov 27 '17 at 17:22
  • @Андрей: Ну, в первой половине вопроса команда в ProductViewModel. – VladD Nov 27 '17 at 17:23
  • @Андрей, именно! Мне нужна команда в MainPageViewModel, подписать на нее обработчик с параметром пункта, на который нажму. Я все сделал, только не могу понять, как кнопку подвязать на эту команду, так как она хочет привязываться только на команду, которая во внутренней VM – Bretbas Nov 27 '17 at 17:24
  • Не могу найти правильный дубликат. Дело в том, что ItemsControl устанавливает своим элементам DataContext, поэтому вам нужно воспользоваться RelativeSource, как по ссылке выше – Андрей NOP Nov 27 '17 at 17:28
  • 1
    <Button Command="{Binding DataContext.RequestCalculatorPriceProduct, RelativeSource={RelativeSource FindAncestor, AncestorType=Window}}" CommandParameter="{Binding}"/> – Андрей NOP Nov 27 '17 at 17:31
  • Блин, что-то не работает... А что нужно передавать в AncestorType – Bretbas Nov 27 '17 at 17:38
  • А MainPageViewModel вы как устанавливаете в качестве контекста? – Андрей NOP Nov 27 '17 at 17:40
  • Я ввел базовый класс BasePage where VM :BasePageViewModel, который внутри себя, создает ViewModel и задает его в качестве контекста. Потом когда наследуюсь, устанавливаю нужную VM в параметре дженерика и все – Bretbas Nov 27 '17 at 17:45
  • Покажите как вы устанавливаете DataContext окну или что там у вас – Андрей NOP Nov 27 '17 at 17:47
  • У меня только одно окно со своим VM, которое управляет переходами между страницами. Каждая страница наследуется от BasePage<VM> : Page where VM : BasePageViewModel. В этом базовом классе для страниц, объявлено свойство, при установке которого задается контекст в сеттере: `set { if( viewModel == value ) return;
    viewModel = value;
    this.DataContext = viewModel;
    

    }`

    – Bretbas Nov 27 '17 at 17:51
  • 1
    У вас Page, ну значит AncestorType=Page – Андрей NOP Nov 27 '17 at 18:00
  • @Андрей Работает. Спасибо большое. А не могли бы объяснить, как за счет такой привязки CommandParameter="{Binding}" он понимает, какой конткретно ProductViewModel передавать? – Bretbas Nov 27 '17 at 18:04
  • 1
    Как я и говорю, ItemsControl устанавливает каждому элементу элемент из привязанной коллекции в качестве DataContext – Андрей NOP Nov 27 '17 at 18:44

0 Answers0