【问题标题】:How do you make the WPF Datagrid select a cell when you first tab into it当您第一次进入单元格时,如何使 WPF Datagrid 选择一个单元格
【发布时间】:2012-01-13 11:36:46
【问题描述】:

当我进入 WPF Datagrid 时,它聚焦第一个单元格(带有一个矩形)但没有选择它(蓝色)。如果我再次按 Tab 键,它会聚焦 选择它。

我认为 DataGridCell 实际上具有 IsSelected=true,但它没有被涂成蓝色。我尝试过修改数据网格和视觉状态,但是当您第一次进入选项卡时,我无法让它正确地重新绘制网格。

以前有人见过这种情况吗?你有解决办法吗?

要重现的代码:

MainWindow.xaml

<Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBox Width="100"/>
        <DataGrid SelectionMode="Single" SelectionUnit="Cell"
              ItemsSource="{Binding MyItems}" AutoGenerateColumns="True"/>
    </StackPanel>
</Window>

MainWindow.xaml.cs

using System.Collections.Generic;
using System.Windows;

namespace WpfApplication1
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            MyItems.Add(new Thingy() { Name = "Frank", Age = 34 });
            MyItems.Add(new Thingy() { Name = "Jim", Age = 43 });
            MyItems.Add(new Thingy() { Name = "Bob", Age = 56 });
            MyItems.Add(new Thingy() { Name = "Harry", Age = 23 });

            DataContext = this;
        }

        private List<Thingy> _myItems = new List<Thingy>();
        public List<Thingy> MyItems
        {
            get { return _myItems; }
        }
    }

    public class Thingy
    {
        public string Name { get; set; }
        public int Age { get; set; }
    }
}

点击文本框,然后点击 tab --- 单元格 1 未被选中

再次点击标签 --- 单元格 2 被选中

非常感谢任何帮助,谢谢。

更新:

当 SelectionUnit=FullRow 时,我在下面显示的几行中取得了一些成功,如果 SelectedIndex 在创建时设置为 0,那么现在第一行 被选择为蓝色。它仍然需要一些工作来处理 shift-tab 等。但是仍然存在一个问题,因为当我将 SelectionMode 更改为扩展并按 shift-downarrow 时,第二行被选中但第一行未被选中(它们都应该被选中) .如果我再次选择第 2+3 行,这是正确的,之后它会继续正常工作。

protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnIsKeyboardFocusWithinChanged(e);

        int oldIdx = this.SelectedIndex;
        this.SelectedIndex = -1;
        this.SelectedIndex = oldIdx;
    }

进一步更新:

通过设置私有 _selectionAnchor 字段解决了该问题。 (感谢 ILSpy)

 protected override void OnIsKeyboardFocusWithinChanged(DependencyPropertyChangedEventArgs e)
    {
        base.OnIsKeyboardFocusWithinChanged(e);

        this.SelectedIndex = -1;
        this.SelectedIndex = 0;

        SelectionAnchor = SelectedCells[0];
    }

    protected DataGridCellInfo? SelectionAnchor
    {
        get
        {
            return typeof(DataGrid).GetField("_selectionAnchor", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(this) as DataGridCellInfo?;
        }
        set
        {
            typeof(DataGrid).GetField("_selectionAnchor", BindingFlags.Instance | BindingFlags.NonPublic).SetValue(this, value);
        }
    }

【问题讨论】:

  • 我认为你需要使用 hasfocus 但不是肯定的,所以我不发布作为答案。
  • 奇怪的是,我在调试期间尝试窥探DataGrid 的属性时得到了StackOverflowException

标签: wpf datagrid


【解决方案1】:

我知道我的回答为时已晚,但它会帮助其他人导航到此站点。

经过大量研究,我得到了如何在选项卡时选择元素的答案。 这真的很简单,只需 XAML 中的一行代码就可以解决问题;

 <Style TargetType="{x:Type DataGridCell}">
     <Setter Property="IsTabStop" Value="False"/>
 </Style>

通过将IsTabStop 设置为false,您是在告诉datagridcell 的可视化树进入其模板并找到任何可以聚焦的元素。如果它找到某个元素,则聚焦该元素。

【讨论】:

    【解决方案2】:

    你可以这样做。注册获得焦点事件,然后将原始源设置为选定项。

    <Window x:Class="WpfApplication1.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    Title="MainWindow" Height="350" Width="525">
    <StackPanel>
        <TextBox Width="100"/>
        <DataGrid SelectionMode="Single" SelectionUnit="Cell"
              ItemsSource="{Binding MyItems}" AutoGenerateColumns="True"  
                GotFocus="WPF_DataGrid_GotFocus" />
    </StackPanel>
    </Window>
    

    然后在文件后面的代码中:

        private void WPF_DataGrid_GotFocus(object sender, RoutedEventArgs e)
        {
            (e.OriginalSource as DataGridCell).IsSelected = true;
    
        }
    

    希望对你有帮助!

    【讨论】:

    • 我实际上已经放弃了 DataGrid 控件并返回到 ListView,在那里我可以更好地控制这种行为。我将其标记为答案,因为它听起来是正确的,而且它是我唯一得到的,感谢 GuruC!
    • 如果DataGrid.SelectionUnitFullRow,那么您必须使用VisualTreeHelper 将可视化树从e.OriginalSourceDataGridCell)向上移动到父DataGridRow。然后,您必须在行上而不是在单元格上设置 IsSelected = true。除此之外,此解决方案有效。
    • 如果DataGridCell 可以编辑,这可能会抛出NullReferenceException,例如双击,因为e.OriginalSourceTextBox。我建议if(e.OriginalSource is DataGridCell dataGridCell) dataGridCell.IsSelected = true;
    【解决方案3】:

    如果 CodeBehind 是一个选项,则以下代码设置 selectedItem:

    private void CrashGrid_OnGotKeyboardFocus(object sender, RoutedEventArgs e)
    {
        (DataGrid)e.Source.SelectedItem = (DataGrid)e.Source.CurrentCell.Item;
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-11-01
      • 2016-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-07
      相关资源
      最近更新 更多