Mvvm ListView wpf как обработать нажатия в ModelView

Как можно обработать событие в MV
DelegateCommand.cs

 class DelegateCommand : ICommand
    {
        Action<object> execute;
        Func<object, bool> canExecute;


        public event EventHandler CanExecuteChanged;


        public DelegateCommand(Action<object> execute, Func<object, bool> canExecute)
        {
            this.execute = execute;
            this.canExecute = canExecute;
        }

        public DelegateCommand(Action<object> execute)
        {
            this.execute = execute;
            this.canExecute = this.AlwaysCanExecute;
        }

        public DelegateCommand()
        {

        }
        
        public void Execute(object param)
        {
            execute(param);
        }

        public bool CanExecute(object param)
        {
            return canExecute(param);
        }


        public void RaiseCanExecuteChanged()
        {
            if (CanExecuteChanged != null)
                CanExecuteChanged(this, EventArgs.Empty);
        }

      
        private bool AlwaysCanExecute(object param)
        {
            return true;
        }
}

MainWindow.xaml

                <ListView Width="1031" ItemsSource="{Binding GetTopItem}" 
                           ScrollViewer.VerticalScrollBarVisibility="Disabled" HorizontalAlignment="Left" ScrollViewer.HorizontalScrollBarVisibility="Hidden" 
                           Background="{x:Null}" BorderBrush="{x:Null}" Foreground="#DD000000">
                    <ListView.DataContext>
                        <vm:BookMainVM/>
                    </ListView.DataContext>
                    <ListView.ItemsPanel>
                        <ItemsPanelTemplate>
                            <StackPanel Orientation="Horizontal" HorizontalAlignment="Left"></StackPanel>
                        </ItemsPanelTemplate>
                    </ListView.ItemsPanel>
                    
                    <ListView.ItemTemplate>
                        <DataTemplate>
                            
                            <Border HorizontalAlignment="Left" CornerRadius="25,25,25,25"  BorderThickness="1" BorderBrush="#FF474747" Height="288" Margin="0,0,0,0" >
                                <Grid   Grid.Column="0" Height="Auto" Width="216" Margin="-1">
                                    <Grid.RowDefinitions>
                                        <RowDefinition Height="49*"/>
                                        <RowDefinition Height="5*"/>
                                        <RowDefinition Height="18*"/>
                                    </Grid.RowDefinitions>
                                    <Border CornerRadius="25,25,0,0" RenderTransformOrigin="0.5,0.5">
                                        <Border.Background>
                                            <ImageBrush ImageSource="{Binding Img_src}" Stretch="Fill" />
                                        </Border.Background>
                                    </Border>
                                    <Label Content="{Binding Rate}"  Background="#FFBFBFBF" RenderTransformOrigin="0.5,0.5" Grid.Row="1" FontSize="11" FontFamily="Meiryo UI" HorizontalContentAlignment="Center"/>
                                    <Border CornerRadius="0,0,25,25"  Grid.Row="2" Background="#FF8F8F8F">
                                        <TextBlock  Margin="6,0,0,0" Text="{Binding Name}" HorizontalAlignment="Left" TextWrapping="Wrap"  VerticalAlignment="Top" Grid.Row="2" Height="61" Width="190"/>
                                    </Border>
                                </Grid>
                            </Border>
                        </DataTemplate>
                    </ListView.ItemTemplate>
                </ListView>

Как при нажатии на элемент коллекции нужно как-то обработать это в MV и там получить данные Text="{Binding Name}. Я уже перепробовал много способов и в итоге решил спросить


Ответы (1 шт):

Автор решения: VladD

Например, так:

  1. В вашу VM для элемента списка положите свойство Activate типа ICommand, и пропишите в него экземпляр DelegateCommand

  2. В вашем XAML укажите InputBindings:

    <ListView.ItemTemplate>
        <DataTemplate>
            <Border ... >
                <Border.InputBindings>
                    <MouseBinding Gesture="LeftClick" Command="{Binding Activate}"/>
                </Border.InputBindings>
    

Вроде бы всё.


Пример структуры VM:

class MainVM
{
    public ObservableCollection<ItemVM> GetTopItem { get; }

    public MainVM()
    {
        var itemVMs = new List<ItemVM>();
        foreach (Item item in Model.GetItems())
            itemVMs.Add(new ItemVM(item));
        GetTopItem = new ObservableCollection<ItemVM>(itemVMs);
    }
}

class ItemVM
{
    Item item;
    public ItemVM(Item item)
    {
        this.item = item;
        Activate = new DelegateCommand(o => MessageBox.Show(item.Id.ToString()));
    }

    public ICommand Activate { get; }
}

Если совсем не хочется иметь дело с несколькими VM, можно сделать так. Вместо ObservableCollection<ItemVM> выставить ObservableCollection<Item>. Activate положить в MainVM:

class MainVM
{
    public ObservableCollection<Item> GetTopItem { get; }

    public MainVM()
    {
        GetTopItem = new ObservableCollection<Item>(Model.GetItems());
        Activate = new DelegateCommand(o =>
        {
            var item = (Item)o;
            MessageBox.Show(item.Id.ToString());
        });
    }
    public ICommand Activate { get; }
}

Подправить XAML согласно рекомендации @aepot:

<MouseBinding Gesture="LeftClick"
              Command="{Binding DataContext.Activate, RelativeSource={RelativeSource AncestorType=ListView}}"
              CommandParameter="{Binding}"/>

У меня такое работает, проверил.

→ Ссылка