WPF中类似Windows资源管理器的LIstView键盘导航
我希望在Windows资源管理器的图标视图中有键盘导航,即如果移动到屏幕宽度的末尾,则选择的内容应移动到下一行WPF中类似Windows资源管理器的LIstView键盘导航,wpf,mvvm,keyboard-navigation,Wpf,Mvvm,Keyboard Navigation,我希望在Windows资源管理器的图标视图中有键盘导航,即如果移动到屏幕宽度的末尾,则选择的内容应移动到下一行 <ListView Name="lv" Grid.Row="1" Width="Auto" Height="Auto" IsTextSearchEnabled="True" ItemsSource="{Binding Path=Per
<ListView Name="lv"
Grid.Row="1"
Width="Auto"
Height="Auto"
IsTextSearchEnabled="True"
ItemsSource="{Binding Path=Persons}"
KeyboardNavigation.DirectionalNavigation="Continue"
SelectedItem="{Binding Path=SelectedPerson}"
SelectionMode="Single"
View="{StaticResource ResourceKey=plainView}">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}" BasedOn="{StaticResource {x:Type ListViewItem}}">
<Style.Triggers>
<DataTrigger Binding="{Binding Path=IsSelected}" Value="True">
<Setter Property="IsEnabled" Value="False"></Setter>
</DataTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
</ListView>
在Generic.xaml中定义ListView默认样式,如下所示:
<Style TargetType="{x:Type ListView}">
<Setter Property="SnapsToDevicePixels" Value="true" />
<Setter Property="ScrollViewer.HorizontalScrollBarVisibility" Value="Visible" />
<Setter Property="ScrollViewer.VerticalScrollBarVisibility" Value="Visible" />
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="FontFamily" Value="Trebuchet MS" />
<Setter Property="FontSize" Value="12" />
<Setter Property="BorderBrush" Value="{DynamicResource ControlBorderBrush}" />
<Setter Property="BorderThickness" Value="1" />
<Setter Property="Padding" Value="1" />
<Setter Property="IsTabStop" Value="False" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListView}">
<Grid>
<Border x:Name="Border"
Background="{DynamicResource ControlBackgroundBrush}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="1">
<ScrollViewer Margin="{TemplateBinding Padding}" IsTabStop="False">
<ItemsPresenter/>
</ScrollViewer>
</Border>
<Border x:Name="DisabledVisualElement"
Background="#A5FFFFFF"
BorderBrush="#66FFFFFF"
BorderThickness="1"
IsHitTestVisible="false"
Opacity="0" />
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="false">
<Setter TargetName="DisabledVisualElement" Property="Opacity" Value="1" />
</Trigger>
<Trigger Property="IsGrouping" Value="true">
<Setter Property="ScrollViewer.CanContentScroll" Value="false" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
<Setter Property="ItemsPanel">
<Setter.Value >
<ItemsPanelTemplate>
<WrapPanel Height="{Binding ActualHeight,
RelativeSource={RelativeSource AncestorType=Border}}"
MinWidth="{Binding (ListView.View).MinWidth,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListView}}}"
Focusable="False"
IsItemsHost="True"
KeyboardNavigation.DirectionalNavigation="Contained"
ItemWidth="{Binding (ListView.View).ItemWidth,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type ListView}}}"
Orientation="Vertical" />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
</Style>
小说明:您的
WrapPanel
占用了您的ScrollViewer
的所有可用大小,这实际上是无限的。如果你想让你的项目在垂直包装中滚动,你应该在水平宽度中限制你的高度。我发现实现这一点的唯一方法是手动解释
PreviewKeyDown事件并设置selectedindex。
您必须将handled设置为true,否则listview也将解释键,这将导致错误的键导航
下面是一个带有两个键的示例:
private void listView_PreviewKeyDown(object sender, KeyEventArgs e)
{
if (listView.SelectedIndex >= 0)
{
if (e.Key == Key.Right)
{
listView.SelectedIndex++;
}
if (e.Key == Key.Left)
{
listView.SelectedIndex--;
}
e.Handled = true;
}
}
编辑:使用MVVMLight工具包的100%纯MVVM方式
XAML:
xmlns:mvvmLight=“clr命名空间:GalaSoft.mvvmLight.Command;assembly=GalaSoft.mvvmLight.Extras.WPF4”
xmlns:i=“clr命名空间:System.Windows.Interactivity;assembly=System.Windows.Interactivity”
>
视图模型:
public ICommand PreviewKeyDownCommand
{
get
{
return new RelayCommand<Object>(x => this.PreviewKeyDown(x as KeyEventArgs));
}
}
private void PreviewKeyDown(KeyEventArgs e)
{
if (SelectedIndex >= 0)
{
if (e.Key == Key.Right)
{
SelectedIndex++;
}
if (e.Key == Key.Left)
{
SelectedIndex--;
}
}
e.Handled = true;
}
private int _selectedIndex;
public int SelectedIndex
{
get { return _selectedIndex; }
set
{
_selectedIndex = value;
NotifyPropertyChanged("SelectedIndex");
}
}
public ICommand previewkeydown命令
{
得到
{
返回新的RelayCommand(x=>this.PreviewKeyDown(x为KeyEventArgs));
}
}
私有void PreviewKeyDown(KeyEventArgs e)
{
如果(已选择索引>=0)
{
如果(e.Key==Key.Right)
{
选择dex++;
}
如果(e.Key==Key.Left)
{
选择索引--;
}
}
e、 已处理=正确;
}
私有int_选择的索引;
公共整数选择索引
{
获取{return\u selectedIndex;}
设置
{
_selectedIndex=值;
NotifyPropertyChanged(“SelectedIndex”);
}
}
我也尝试了键盘导航。DirectionalNavigation=“Cycle”
通过这样做,我的导航现在包含在。。。也就是说,如果我到达宽度的末尾(通过使用键盘的右键),它会停在那里,我希望它移动到下一行……这是参与导航场景的FocusNavigationDirection
enum,如果是WrapPanel,当你按键盘上的光标键时,你将只在一行的边界内导航(左、右)或一列(上、下)除了编写你自己的聚焦场景提供商之外,没有其他解决方案了。是的,看起来……那么你能给我一些关于编写这种导航提供商的指导吗?谢谢你的回答,但是我使用的是MVVM,所以我不希望有代码隐藏……我们能为你的上述方法做些什么吗???好的,我编辑了我的帖子并补充道MVVM方法。我使用MVVM light toolkit将Keydown事件传递给VM,并将SelectedIndex绑定到ListView。更好的方法是创建一个行为正确的CustomControl。除此之外,MVVM完全可以使用Keydown事件并将其传递给ViewModel。感谢您的编辑……但我在这里遇到的问题是m垂直包装,所以当我按下右键时,我希望转到Adcent columns对象,但在您的情况下,它不起作用,因为它会移动到上一个或下一个选定的项目。另外,通过附加行为可以避免将KeyEventArgs带到ViewModel中
我编写的代码已经在使用您的代码了…如果您愿意,我会发布,但我的上述行为仍然有效t陈述了问题所在
public ICommand PreviewKeyDownCommand
{
get
{
return new RelayCommand<Object>(x => this.PreviewKeyDown(x as KeyEventArgs));
}
}
private void PreviewKeyDown(KeyEventArgs e)
{
if (SelectedIndex >= 0)
{
if (e.Key == Key.Right)
{
SelectedIndex++;
}
if (e.Key == Key.Left)
{
SelectedIndex--;
}
}
e.Handled = true;
}
private int _selectedIndex;
public int SelectedIndex
{
get { return _selectedIndex; }
set
{
_selectedIndex = value;
NotifyPropertyChanged("SelectedIndex");
}
}