R. Andrei
R. Andrei

Reputation: 45

Bind keypress event to ListViewItem in WPF

I have a ListView which populates the view with ListViewItems containing an image and text(file browser). How can I fire a Command when the user presses the 'Enter' key on a selected item while respecting the MVVM design pattern? I've searched and found a few solutions, but none of them seem to work for me.

<ListView ScrollViewer.HorizontalScrollBarVisibility="Hidden"
          VirtualizingPanel.IsVirtualizing="True"
          VirtualizingPanel.ScrollUnit="Item"
          Background="#fdfaf4"
          Name="filesView"
          ItemsSource="{Binding Items}">

    <ListView.ItemTemplate>
        <DataTemplate>

            <!-- The image and item name -->
            <Grid Width="{Binding ActualWidth, ElementName=filesView, Converter={x:Static converter:GridWidthToListViewWidthConverter.Instance}}" 
                  Background="Transparent">

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="0.07*" MinWidth="25" MaxWidth="40" />
                    <ColumnDefinition Width="*" />
                </Grid.ColumnDefinitions>

                <!-- Drive, file or folder -->
                <Image Grid.Column="0"
                       Margin="0,0,5,0"
                       Name="itemType"
                       Source="{Binding Type,
                       Converter={x:Static converter:HeaderToImageConverter.Instance}}" />

                <!-- The text is binded to the image size, so they'll expand/shrink together -->
                <TextBlock Grid.Column="1"
                           VerticalAlignment="Center"
                           FontSize="{Binding ActualHeight,
                           ElementName=itemType, Converter={x:Static converter:ImageSizeToFontSizeConverter.Instance}}"
                           Text="{Binding Name}" />

                <!-- The command to enter a drive/folder is called from here -->
                <Grid.InputBindings>
                    <MouseBinding Gesture="LeftDoubleClick" Command="{Binding EnterCommand, Mode=TwoWay}" />
                    <KeyBinding Key="Enter" Command="{Binding EnterCommand, Mode=TwoWay}" />
                </Grid.InputBindings>

            </Grid>

        </DataTemplate>
    </ListView.ItemTemplate>

</ListView>

The MouseBinding works just fine. I've tried putting the KeyBinding in the ListView instead of the grid and getting the focused item with the SelectedItem property but still nothing.

Upvotes: 4

Views: 3537

Answers (2)

mm8
mm8

Reputation: 169360

Implement the PreviewKeyDown event for the root Grid in the ItemTemplate or the ListViewItem container in the code-behind of the view and simply execute the command from there, e.g.:

private void ListViewItem_PreviewKeyDown(object sender, KeyEventArgs e)
{
    var viewModel = DataContext as YourViewModel;
    viewModel.YourCommand.Execute(null);
}

<ListView.ItemContainerStyle>
    <Style TargetType="ListViewItem">
        <EventSetter Event="PreviewKeyDown" Handler="ListViewItem_PreviewKeyDown" />
    </Style>
</ListView.ItemContainerStyle>

Or implement a behaviour that hooks up the event handler and does the same: https://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF.

Neither approach breaks the MVVM pattern since you are invoking the exact same view model command from the exact same view that the XAML markup is a part of.

MVVM is not about eliminating code from the views, it is about separation of concerns. If you invoke the command using a KeyBinding or an event handler doesn't matter.

Upvotes: 4

Fredrik
Fredrik

Reputation: 2317

Try Gesture="Enter";

<Grid.InputBindings>
    <KeyBinding Gesture="Enter" Command="{Binding EnterCommand}" />
</Grid.InputBindings>

Upvotes: 1

Related Questions