Как привязать команду к ListViewItem? MVVM WPF
разработчики:)
Стоит задача привязать команду к ListViewItem для того, чтобы метод команды выполнялся коректно...
Сейчас у меня следующий код: XAML
<ListView ItemsSource="{Binding Source={StaticResource myBaseVM}, Path=GameList}"
SelectedIndex="{Binding Source={StaticResource myBaseVM}, Path=Indexer,
Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
HorizontalContentAlignment="Center"
VerticalContentAlignment="Center">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal" Margin="0,0,0,0" Width="270"
Background="FloralWhite">
<Grid Background="DarkSalmon">
<Image Source="{Binding Icon}" Height="50" Width="50" Margin="5"/>
</Grid>
<StackPanel Grid.Column="1" VerticalAlignment="Center">
<TextBlock Text="{Binding GameName}" HorizontalAlignment="Center"/>
<Button Height="25"
Command="{Binding StartGameCommands, Source={StaticResource myBaseVM}}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Он прекрасно работает при заполнении коллекции, но мне важно определять индекс выделенного элемента в списке.
Для того, чтобы коректно выполнился следующий код: VM
public void StartGame()
{
var a = Indexer;
var b = InfoGame.ElementAt(a).FullPath;
Process.Start(b);
}
Данный метод, по индексу, выполняет поиск пути к игре в коллекции, чтобы её запустить, когда пользователь нажимает на кнопку.
Класс реализующий команду:
**public class StartGameCommands : ICommand
{
public BaseVM baseVM { get; set; }
public StartGameCommands(BaseVM baseVM)
{
this.baseVM = baseVM;
}
public event EventHandler CanExecuteChanged;
public bool CanExecute(object parameter)
{
return true;
}
public void Execute(object parameter)
{
baseVM.StartGame();
}
}**
Но проблема в том, что при нажатии на кнопку индекс еще не успевает определиться, поэтому он всегда равен нулю. А если сначала щелкнуть просто на элемент рядом с кнопкой, то он определиться коректно.

Возможно ли как-то привязать команду непосредственно к ListViewItem ? Или как то переписать XAML код, чтобы индекс определялся сразу, как только пользователь нажмёт на кнопку ?
Ответы (1 шт):
Вам нужна реализация команды, которая позволит передать параметр.
Например эта.
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter) => _canExecute == null || _canExecute(parameter);
public void Execute(object parameter) => _execute(parameter);
}
Далее во вьюмодели объявите свойство
public ICommand StartGameCommand { get; }
И присвойте значение в конструкторе. Так как я не знаю, какого типа коллекция InfoGame, пусть будет это ObservableCollection<GameInfo>. Тогда код будет такой.
public BaseVM()
{
StartGameCommand = new RelayCommand(parameter =>
{
var info = (GameInfo)parameter;
Process.Start(info.FullPath);
}, parameter => parameter is GameInfo); // CanExecute задизаблит кнопку, если параметр не нужного типа, например если он null
}
В разметке это будет выглядеть так
<Button Height="25"
Command="{Binding StartGameCommand, Source={StaticResource myBaseVM}}"
CommandParameter="{Binding}"/>
Кстати, такая реализация команды позволяет использовать один универсальный RelayCommand для всех команд, передавая исполняемую часть команды как делегат в виде лямбда-выражения. Очень удобно. Так же поддерживает CanExecute. Он необязателен, и его можно выбросить при создании команды, но я бы на вашем месте изучил полезность этой функции команды.