将按键事件绑定到WPF中的ListViewItem

4

我有一个ListView,它通过包含图像和文本(文件浏览器)的ListViewItems填充视图。当用户按下所选项目上的“Enter”键时,我该如何触发命令并遵守MVVM设计模式?我搜索过并找到了一些解决方案,但似乎都对我无效。

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

鼠标绑定正常工作。我尝试将KeyBinding放在ListView而不是网格中,并使用SelectedItem属性获取焦点项目,但仍然没有效果。


1
为什么你找到的解决方案对你无效?你的问题是什么?是否有任何异常或意外行为?请具体描述。 - dymanoid
问题在于当我按下“Enter”键时,没有任何反应。处理程序函数未被调用。 - R. Andrei
2个回答

4

在视图的代码后台中,为根GridItemTemplateListViewItem容器实现PreviewKeyDown事件,并从那里简单地执行命令,例如:

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>

或者实现一个行为来挂钩事件处理程序并执行相同的操作:https://www.codeproject.com/Articles/28959/Introduction-to-Attached-Behaviors-in-WPF

这两种方法都不会破坏MVVM模式,因为您是在与XAML标记一起的确切视图中调用相同的视图模型命令。

MVVM并不是要从视图中消除代码,而是要实现关注点分离。如果使用KeyBinding或事件处理程序调用命令并不重要。


网格需要聚焦。您也可以处理ListView本身的PreviewKeyDown事件。 - mm8
看一下我编辑后的答案,里面有一个如何连接ListViewItem事件处理程序的示例。 - mm8
之前不可用。但我按照你说的做了,现在按下按钮时会被调用。唯一的问题是,当我尝试将DataContext(或sender)分配给该项时,我会收到NullReferenceException。看起来这个sender和this都是null... - R. Andrei
“Assign DataContext…”?我不明白。这与您最初的问题——捕获单击事件并处理它有什么关系? - mm8
1
找到问题了!我需要执行以下代码:var viewModel = (sender as ListViewItem).Content as MyViewModel; 然后再执行命令。非常感谢您的帮助! - R. Andrei
显示剩余11条评论

0
尝试使用 Gesture="Enter"
<Grid.InputBindings>
    <KeyBinding Gesture="Enter" Command="{Binding EnterCommand}" />
</Grid.InputBindings>

尝试了,但没有任何反应...根据我所读的,这可能与键盘无法聚焦于视图项目有关。 - R. Andrei
可能会有其他控件“吞噬”某些键组合。按照我的建议处理PreviewKeyDown事件,你就没问题了。 - mm8

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接