gpt4 book ai didi

wpf - 如何以编程方式在 WPF ListView 中设置选择标记(焦点项目)

转载 作者:行者123 更新时间:2023-12-04 05:09:31 25 4
gpt4 key购买 nike

这个问题在这里已经有了答案:





Set Item Focus in ListView WPF

(5 个回答)


9年前关闭。




我找不到在 WPF ListView 中以编程方式设置焦点项目的方法。我只能找到 Selected Item | 的变体项目 |索引 |值,但 'Focused' 项目与 'selected' 项目没有直接关系 - 可以不选择焦点项目(例如,当使用 Ctrl+Click 取消选择当前项目时)。

简而言之-我想从下面提供的代码中获得以下行为(它用虚拟的 8 个项目填充虚拟 ListView ,并在按下 X 时尝试从末尾开始关注第二个项目):

想要的行为:

  • 使用鼠标 - 选择第二项
  • 按 X - 这将关注从末尾开始的第二个项目
  • 按键盘上的“向下”数组 - 这应该将当前选择移动到最后一项

  • 实际发生了什么:
  • 使用鼠标 - 选择第二项
  • 按 X - 这将选择从末尾开始的第二个项目,但焦点仍然在从开始
  • 开始的第二个项目上
  • 按键盘上的“向下”数组 - 这应该将当前选择移动到最后一项,但选择的是第三项。

  • 注意:普通的 Win32 API(当然,与 WPF 完全不同)有 LVM_SETSELECTIONMARK 消息。我在 WPF 中找不到类似的东西。它存在吗?

    示例 XAML:
    <Window x:Class="WpfListviewTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow" Height="350" Width="525">
    <ListView x:Name="List1" KeyDown="List1_KeyDown">
    <ListView.View>
    <GridView>
    <GridViewColumn Width="140" Header="Column 1" />
    <GridViewColumn Width="140" Header="Column 2" />
    <GridViewColumn Width="140" Header="Column 3" />
    </GridView>
    </ListView.View>
    <sys:DateTime>1/2/3</sys:DateTime>
    <sys:DateTime>4/5/6</sys:DateTime>
    <sys:DateTime>7/8/9</sys:DateTime>
    <sys:DateTime>10/11/12</sys:DateTime>
    <sys:DateTime>1/2/3</sys:DateTime>
    <sys:DateTime>4/5/6</sys:DateTime>
    <sys:DateTime>7/8/9</sys:DateTime>
    <sys:DateTime>10/11/12</sys:DateTime>
    </ListView>
    </Window>

    示例代码隐藏:
    public partial class MainWindow : Window {
    public MainWindow() {
    InitializeComponent();
    }

    private void List1_KeyDown(object sender, KeyEventArgs e) {
    if( e.Key == Key.X ) {
    List1.SelectionMode = SelectionMode.Single;
    List1.SelectedIndex = List1.Items.Count - 2;
    }
    }
    }

    最佳答案

    感谢 Mic 回答中的链接,我获得了更多有用的信息,并为我的案例找到了可行的解决方案。

    一些背景资料:

  • 与 ListView 控件的其他实现不同(在 WinForms 或 Win32 中),WPF 的 ListView 版本没有像 FocusedItem 这样的东西。似乎 MS 决定使用 UIElement 的通用接口(interface)将项目集中在 ListView 中,每个视觉 ListViewItem 都是其后裔。这导致我的用例在 WPF 中变得更加复杂。
  • WPF ListView 中的可视项可以通过 ListView.ItemContainerGenerator.ContainerFromIndex(index) as ListViewItem 获取这个项目有 Focus()确实需要功能的方法。然而,在虚拟化 ListView 中,这不适用于当前可见区域之外的项目 - 它们尚未创建并且方法返回 null :(
  • 这就是为什么首先需要使要聚焦的项目可见。这可以通过 ScrollViewer 完成。在 ListView 中使用其 ScrollToVerticalOffset()方法(您需要知道要滚动到的项目的索引 - 可以使用 ListView.Items.IndexOf() 来完成)。
  • 接下来,不幸的是,listview 项目不会在编程滚动完成后立即创建 - 这就是为什么实际聚焦可以在一段时间后完成,当创建新的可见项目时。我为此找到了合适的事件 - ListView.LayoutUpdated。
  • 侧节点:
  • ListView.ScrollIntoView(object item)方法似乎是获得相同的“ native 路径”,但是当列表在不同位置包含相当相等的项目时,它不能可靠地工作。 ListView 没有类似 ListView.ScrollIndexIntoView(int index) 的内容.
  • 似乎上面的大部分员工都可以通过单一方法 VirtualizingStackPanel.BringIndexIntoView() ,但 MS 决定对其进行保护,因此无法从外部访问...

  • 这是工作解决方案

    示例 XAML:
    <Window x:Class="WpfListviewTest.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:sys="clr-namespace:System;assembly=mscorlib"
    Title="MainWindow" Height="150" Width="525">
    <ListView x:Name="List1" KeyDown="List1_KeyDown" LayoutUpdated="List1_LayoutUpdated">
    <ListView.View>
    <GridView>
    <GridViewColumn Width="140" Header="Column 1" />
    <GridViewColumn Width="140" Header="Column 2" />
    <GridViewColumn Width="140" Header="Column 3" />
    </GridView>
    </ListView.View>
    <sys:DateTime>1/2/3</sys:DateTime>
    <sys:DateTime>4/5/6</sys:DateTime>
    <sys:DateTime>7/8/9</sys:DateTime>
    <sys:DateTime>10/11/12</sys:DateTime>
    <sys:DateTime>1/2/3</sys:DateTime>
    <sys:DateTime>4/5/6</sys:DateTime>
    <sys:DateTime>7/8/9</sys:DateTime>
    <sys:DateTime>10/11/12</sys:DateTime>
    </ListView>
    </Window>

    示例代码隐藏:
    public partial class MainWindow : Window {
    public MainWindow() {
    InitializeComponent();
    }

    private int? _indexToFocus;

    private void List1_KeyDown(object sender, KeyEventArgs e) {
    switch( e.Key ) {
    case Key.S:
    FocusItemByIndex(1); break;
    case Key.X:
    FocusItemByIndex(List1.Items.Count - 2); break;
    case Key.Z:
    List1.ScrollIntoView(List1.Items[List1.Items.Count - 2]); break;
    }
    }

    public void FocusItemByIndex(int index) {
    ScrollViewer sv = FindChild<ScrollViewer>(List1);
    double firstVisible = sv.VerticalOffset;
    double lastVisible = firstVisible + sv.ViewportHeight;

    if( index > lastVisible ) {
    double topVisible = index - sv.ViewportHeight + 1;
    sv.ScrollToVerticalOffset(topVisible);
    }
    else if( index < firstVisible ) {
    sv.ScrollToVerticalOffset(index);
    }

    _indexToFocus = index;
    }

    public static T FindChild<T>(DependencyObject parent, string name = null)
    where T : DependencyObject
    {
    if( parent == null )
    return null;

    int cChildren = VisualTreeHelper.GetChildrenCount(parent);
    T result = null;

    for( int i = 0; (result == null) && (i < cChildren); i++ ) {
    DependencyObject child = VisualTreeHelper.GetChild(parent, i);
    T tChild = child as T;

    if( tChild != null ) {
    if( name == null ) {
    result = (T)child;
    }
    else {
    FrameworkElement feChild = child as FrameworkElement;

    if( feChild != null && feChild.Name == name )
    result = (T)child;
    }
    }

    if( result == null )
    result = FindChild<T>(child, name);
    }

    return result;
    }

    private void List1_LayoutUpdated(object sender, EventArgs e) {
    if( _indexToFocus != null ) {
    ItemContainerGenerator lvItems = List1.ItemContainerGenerator;
    ListViewItem lvitemToFocus = lvItems.ContainerFromIndex(_indexToFocus.Value) as ListViewItem;

    if( lvitemToFocus != null ) {
    lvitemToFocus.Focus();
    _indexToFocus = null;
    }
    }
    }
    }

    关于wpf - 如何以编程方式在 WPF ListView 中设置选择标记(焦点项目),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15045671/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com