首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Vi通过DataGrid

Vi通过DataGrid
EN

Stack Overflow用户
提问于 2013-09-09 17:13:42
回答 1查看 131关注 0票数 0

我使用一个DataGrid来显示一堆数据。我有SelectionMode="Extended"SelectionUnit="FullRow"

我想要做的是按J将焦点向下移动到网格中,按K在网格中向上移动,然后按x将焦点行添加/删除到SelectedItems列表中(基本上就像gmail中的键盘快捷键)。

我对wpf很在行,但我还没有做到这一点。我不确定行焦点是否与所选的项目分开,但我想到底是什么原因,也许这里有人做了类似的事情。

以下是我迄今所尝试的

代码语言:javascript
复制
case Key.X:
{
    resultsGrid.SelectedItems.Add(resultsGrid.SelectedItem);
    e.Handled = true;
    break;
}
case Key.J:
{
    //down
    var currow = (DataGridRow) resultsGrid.ItemContainerGenerator.ContainerFromItem(resultsGrid.SelectedItem);
    currow.MoveFocus(new TraversalRequest(FocusNavigationDirection.Down));
    //if (resultsGrid.SelectedIndex + 1 >= resultsGrid.Items.Count)
    //    resultsGrid.SelectedIndex = 0;
    //else
    //    resultsGrid.SelectedIndex++;
    break;
}
case Key.K:
{
    //up
    var currow =
        (DataGridRow) resultsGrid.ItemContainerGenerator.ContainerFromItem(resultsGrid.SelectedItem);
    currow.MoveFocus(new TraversalRequest(FocusNavigationDirection.Up));
    //if (resultsGrid.SelectedIndex - 1 <= 0)
    //    resultsGrid.SelectedIndex = resultsGrid.Items.Count - 1;
    //else
    //    resultsGrid.SelectedIndex--;
    break;
}

当前行不向上或向下移动。我也尝试过FocusNavigationDirection.PreviousNext,它们也不会转移焦点。如果我按索引,它会移动,但按X键不会添加到所选项目的列表中。似乎多个select不想启动,直到您使用shift和上/下鼠标单击。

编辑

好的,我已经知道了如何使用jk键导航,但是选择仍然不起作用。如果我向上或向下移动,它会清除所选内容,同时按x也不会做任何事情,至少在视觉上是这样的。

代码语言:javascript
复制
case Key.X:
    resultsGrid.SelectedItems.Add(resultsGrid.SelectedItem);
    e.Handled = true;
    break;
case Key.J:
    {
        //down
        InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Down)
        {
            RoutedEvent = Keyboard.KeyDownEvent
        });
        resultsGrid.ScrollIntoView(resultsGrid.SelectedItem);
        e.Handled = true;
        break;
    }
case Key.K:
    {
        //up
        InputManager.Current.ProcessInput(new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.Up)
        {
            RoutedEvent = Keyboard.KeyDownEvent
        });
        resultsGrid.ScrollIntoView(resultsGrid.SelectedItem);
        e.Handled = true;
        break;
    }
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2013-09-09 21:30:56

如果我正确理解了这个问题,那么每一行都有一个焦点和选择。您希望通过k/j键移动焦点,并通过x键切换选择。

我喜欢在这些情况下使用行为-它需要参考来自blen的System.Windows.Interactivity.dll,但它也提供了一个更干净和模块化的代码。

编辑:--这是我所做的快速POC。它可能需要更多的空引用保护和边缘/边缘情况的处理。

其行为是:

代码语言:javascript
复制
using System;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Interactivity;

namespace GridNavigationTest
{
    public class GridNavigationBehavior : Behavior<DataGrid>
    {
        #region Overrides of Behavior
        /// <summary>
        /// Called after the behavior is attached to an AssociatedObject.
        /// </summary>
        /// <remarks>
        /// Override this to hook up functionality to the AssociatedObject.
        /// </remarks>
        protected override void OnAttached()
        {
            AssociatedObject.PreviewKeyDown += AssociatedObject_KeyDown;
        }

        /// <summary>
        /// Called when the behavior is being detached from its AssociatedObject, but before it has actually occurred.
        /// </summary>
        /// <remarks>
        /// Override this to unhook functionality from the AssociatedObject.
        /// </remarks>
        protected override void OnDetaching()
        {
            AssociatedObject.KeyDown -= AssociatedObject_KeyDown;
        }
        #endregion

        #region Event handlers
        void AssociatedObject_KeyDown(object sender, KeyEventArgs e)
        {
            switch (e.Key)
            {
                case Key.J:
                    NavigateGridFocus(FocusNavigationDirection.Up);
                    break;
                case Key.K:
                    NavigateGridFocus(FocusNavigationDirection.Down);
                    break;
                case Key.X:
                    ToggleRowSelection();
                    break;
            }
        } 
        #endregion

        #region Methods
        private void ToggleRowSelection()
        {
            var currentlyFocusedRow = FindCurrentlyFocusedRow();
            if (currentlyFocusedRow == null)
            {
                return;
            }

            var generator = AssociatedObject.ItemContainerGenerator;
            var rowItem = generator.ItemFromContainer(currentlyFocusedRow);
            if (AssociatedObject.SelectionMode == DataGridSelectionMode.Extended)
            {
                if (AssociatedObject.SelectedItems.Contains(rowItem))
                {
                    AssociatedObject.SelectedItems.Remove(rowItem);
                }
                else
                {
                    AssociatedObject.SelectedItems.Add(rowItem);
                }
            }
            else
            {
                AssociatedObject.SelectedItem = AssociatedObject.SelectedItem == rowItem ? null : rowItem;
            }
        }

        private void NavigateGridFocus(FocusNavigationDirection direction)
        {
            var currentlyFocusedRow = FindCurrentlyFocusedRow();
            if (currentlyFocusedRow == null)
            {
                return;
            }

            var traversalRequest = new TraversalRequest(direction);
            var currentlyFocusedElement = Keyboard.FocusedElement as UIElement;
            if (currentlyFocusedElement != null) currentlyFocusedElement.MoveFocus(traversalRequest);
        }

        private DataGridRow FindCurrentlyFocusedRow()
        {
            var generator = AssociatedObject.ItemContainerGenerator;
            if (generator.Status != GeneratorStatus.ContainersGenerated)
            {
                return null;
            }

            for (var index = 0; index < generator.Items.Count - 1; index++)
            {
                var row = generator.ContainerFromIndex(index) as DataGridRow;
                if (row != null && row.IsKeyboardFocusWithin)
                {
                    return row;
                }
            }
            return null;
        }
        #endregion
    }
} 

其用途是:

代码语言:javascript
复制
<Window x:Class="GridNavigationTest.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:gridNavigationTest="clr-namespace:GridNavigationTest"
        xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
        Title="MainWindow"
        Height="350"
        Width="525">
    <Grid>
        <DataGrid ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type gridNavigationTest:MainWindow}}, Path=People}">
            <i:Interaction.Behaviors>
                <gridNavigationTest:GridNavigationBehavior/>
            </i:Interaction.Behaviors>
            <!--This is here just for testing of focus movement-->
            <DataGrid.ItemContainerStyle>
                <Style TargetType="{x:Type DataGridRow}">
                    <Style.Triggers>
                        <Trigger Property="IsKeyboardFocusWithin"
                                 Value="True">
                            <Setter Property="Background"
                                    Value="HotPink" />
                        </Trigger>
                    </Style.Triggers>
                </Style>
            </DataGrid.ItemContainerStyle>
        </DataGrid>
    </Grid>
</Window>

这要求其中一个行将IsKeyboardFocuedWithin设置为true。您可以将初始选择的逻辑分解为行为(或者,在新的行为中)。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18703475

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档