网上到处都是类似的问题,我也搜索过(最接近:[1],[2],[3])。
到目前为止,我无法相信这个问题是丑陋/不平凡的。
我有一个DataGridView。我有其他控件(在这种情况下:在DataGridView的列标题中)。我想支持一个快速的“跳转到网格”命令。此命令需要将键盘焦点设置为网格,以便用户可以使用箭头键在行之间导航。
在下面的家中玩琐碎的测试包。在数据网格中选择一个元素非常容易,但似乎没有一种方法可以让它成为键盘焦点。除了代码隐藏操作,即使这样你似乎必须跳过篮球(见[2],玩杂耍让细胞容器设置键盘焦点,因为..网格和行似乎并不适用于所有我可以告诉)。
看起来很简单?
一些琐碎的模型:
public class Item
{
public int DayOfMonth { get; set; }
public string Weekday { get; set; }
}
匹配简单的viewmodel(假设你有一个RelayCommand实现,请参阅JumpToGrid~~ meat~):
public class MainViewModel : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
private IList<Item> m_items;
public IList<Item> SampleItems
{
get { return m_items; }
set { SetField(ref m_items, value, () => SampleItems); }
}
private Item m_currentItem;
public Item CurrentItem
{
get { return m_currentItem; }
set { SetField(ref m_currentItem, value, () => CurrentItem); }
}
public ICommand JumpToGridCommand { get; private set; }
public MainViewModel()
{
JumpToGridCommand = new RelayCommand(p => JumpToGrid());
var items = new List<Item>();
var today = DateTime.Now;
for (int i = 1; i <= DateTime.DaysInMonth(today.Year, today.Month); i++ )
{
items.Add(new Item { DayOfMonth = i, Weekday = new DateTime(today.Year, today.Month, i).DayOfWeek.ToString() });
}
SampleItems = items;
}
private void JumpToGrid()
{
// I can change the selection just fine
CurrentItem = SampleItems[0];
// But the keyboard focus is broken, up/down doesn't work as expected
}
protected bool SetField<T>(ref T field, T value, Expression<Func<T>> selectorExpression)
{
if (selectorExpression == null) throw new ArgumentNullException("selectorExpression");
MemberExpression body = selectorExpression.Body as MemberExpression;
if (body == null) throw new ArgumentException("The body must be a member expression");
var fieldName = body.Member.Name;
if (EqualityComparer<T>.Default.Equals(field, value)) return false;
field = value;
OnPropertyChanged(fieldName);
return true;
}
protected void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
{
handler(this, new PropertyChangedEventArgs(propertyName));
}
}
}
简单视图(除了加载的事件中的“DataContext = new MainViewModel()”之外,代码隐藏是空的):
<Window x:Class="DataGridKeyboardFocus.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:DataGridKeyboardFocus"
Loaded="Window_Loaded"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid
ColumnWidth="*"
AutoGenerateColumns="False"
Margin="1"
ItemsSource="{Binding SampleItems}"
SelectedItem="{Binding CurrentItem, Mode=TwoWay}"
SelectionUnit="FullRow"
IsReadOnly="True">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding DayOfMonth}">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="Some label" />
<TextBox>
<TextBox.InputBindings>
<KeyBinding Modifiers="Control" Key="Tab" Command="{Binding DataContext.JumpToGridCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" />
</TextBox.InputBindings>
</TextBox>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Weekday}">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="Another label" />
<TextBox>
<TextBox.InputBindings>
<KeyBinding Modifiers="Control" Key="Tab" Command="{Binding DataContext.JumpToGridCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:MainWindow}}}" />
</TextBox.InputBindings>
</TextBox>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
答案 0 :(得分:4)
我为网格添加了选择更改事件并尝试选择一个单元格。请参阅以下代码。
<DataGrid
ColumnWidth="*"
AutoGenerateColumns="False"
Margin="1"
ItemsSource="{Binding SampleItems}"
SelectedItem="{Binding CurrentItem, Mode=TwoWay}"
SelectionUnit="FullRow"
IsReadOnly="True"
SelectionChanged="DataGrid_SelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding DayOfMonth}">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="Some label" />
<TextBox>
<TextBox.InputBindings>
<KeyBinding Modifiers="Control" Key="T" Command="{Binding DataContext.JumpToGridCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
</TextBox.InputBindings>
</TextBox>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
<DataGridTextColumn Binding="{Binding Weekday}">
<DataGridTextColumn.HeaderTemplate>
<DataTemplate>
<StackPanel Orientation="Vertical">
<TextBlock Text="Another label" />
<TextBox>
<TextBox.InputBindings>
<KeyBinding Modifiers="Control" Key="T" Command="{Binding DataContext.JumpToGridCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}}" />
</TextBox.InputBindings>
</TextBox>
</StackPanel>
</DataTemplate>
</DataGridTextColumn.HeaderTemplate>
</DataGridTextColumn>
</DataGrid.Columns>
</DataGrid>
代码背后。
private void DataGrid_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DataGrid dg = sender as DataGrid;
SelectRowByIndex(dg, dg.SelectedIndex);
}
public static DataGridCell GetCell(DataGrid dataGrid, DataGridRow rowContainer, int column)
{
if (rowContainer != null)
{
DataGridCellsPresenter presenter = FindVisualChild<DataGridCellsPresenter>(rowContainer);
if (presenter == null)
{
/* if the row has been virtualized away, call its ApplyTemplate() method
* to build its visual tree in order for the DataGridCellsPresenter
* and the DataGridCells to be created */
rowContainer.ApplyTemplate();
presenter = FindVisualChild<DataGridCellsPresenter>(rowContainer);
}
if (presenter != null)
{
DataGridCell cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
if (cell == null)
{
/* bring the column into view
* in case it has been virtualized away */
dataGrid.ScrollIntoView(rowContainer, dataGrid.Columns[column]);
cell = presenter.ItemContainerGenerator.ContainerFromIndex(column) as DataGridCell;
}
return cell;
}
}
return null;
}
public static T FindVisualChild<T>(DependencyObject obj) where T : DependencyObject
{
for (int i = 0; i < VisualTreeHelper.GetChildrenCount(obj); i++)
{
DependencyObject child = VisualTreeHelper.GetChild(obj, i);
if (child != null && child is T)
return (T)child;
else
{
T childOfChild = FindVisualChild<T>(child);
if (childOfChild != null)
return childOfChild;
}
}
return null;
}
public static void SelectRowByIndex(DataGrid dataGrid, int rowIndex)
{
DataGridRow row = dataGrid.ItemContainerGenerator.ContainerFromIndex(rowIndex) as DataGridRow;
if (row != null)
{
DataGridCell cell = GetCell(dataGrid, row, 0);
if (cell != null)
cell.Focus();
}
}