我面临一个问题,我需要能够真正集中精力TabItem
选项卡中的TabControl
就像我会按TAB
钥匙。我知道我可以使用SendKeys.SendWait("{TAB}");
为了实现这一目标,但我更喜欢更强大的解决方案。
选项卡项绑定到ItemSource
of an ObservableCollection
。该集合包含稍后绑定到选项卡项标题、图标、内容等的视图模型列表。该集合在运行时填充和清空,我没有静态集合。
我制作了一个示例项目来说明该问题(请参阅下面的代码)。
Current behavior after I added a tab item to the collection looks like this:
![New tab isn't focused](https://i.stack.imgur.com/jP508.png)
按左侧的“添加选项卡”按钮后,一个新选项卡将添加到ObservableCollection
然后反映在选项卡控件中的新选项卡项中。
我尝试将新选项卡的重点放在:
- Set the
SelectedItem
of the TabControl
添加新项目后(参见下面的代码)
-
Keyboard.Focus((UIElement)sender)
在选项卡项加载事件中(参见下面的代码)
- 通过设置
FocusManager.FocusedElement="{Binding ElementName=tabHeader}"
在 XAML 中(参见下面的代码)
这些尝试似乎都不起作用。
期望的行为新添加的选项卡项目实际上会获得焦点(就像我会按TAB
key) 看起来像这样:
为了创建这个图像,我按下了TAB
添加新选项卡项目后。
我找不到任何可行的解决方案here https://stackoverflow.com/questions/1227132/how-can-i-make-a-specific-tabitem-gain-focus-on-a-tabcontrol-without-click-event or here https://social.msdn.microsoft.com/Forums/vstudio/en-US/d32ba76f-9c58-4a70-9845-deaf1771fce2/setting-keyboard-focus-after-switch-to-new-tabitem-in-a-tabcontrol?forum=wpf并且Microsoft 有关 Focus 的文档 https://learn.microsoft.com/en-us/dotnet/desktop/wpf/advanced/focus-overview?view=netframeworkdesktop-4.8没有提供足够的光线。
任何提示表示赞赏。
要重现上面的屏幕截图,请使用我的示例项目:
主窗口.xaml
<Window x:Class="WpfAppTabControl.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfAppTabControl"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:MainViewViewModel}"
Title="MainWindow" Height="450" Width="800">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="350"/>
<ColumnDefinition Width="12"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Button Grid.Column="0" Grid.Row="2" Margin="50,50,50,50" Command="{Binding AddTabCommand}">Add Tab</Button>
<GridSplitter Grid.Column="1" Grid.Row="2" ResizeDirection="Columns" ResizeBehavior="PreviousAndNext" HorizontalAlignment="Stretch"/>
<TabControl Grid.Column="2"
Grid.Row="2"
ItemsSource="{Binding ItemsToDisplay}"
SelectedItem="{Binding ActiveTabItem}"
SelectionChanged="OnSelectionChanged"
HorizontalContentAlignment="Stretch"
VerticalContentAlignment="Stretch"
FocusManager.FocusedElement="{Binding ElementName=tabHeader}"
FocusManager.IsFocusScope="True">
<TabControl.ItemContainerStyle>
<Style TargetType="TabItem">
<EventSetter Event="Loaded" Handler="OnTabItemLoaded"/>
<Setter Property="IsSelected" Value="True"/>
<Setter Property="Focusable" Value="True"/>
<Setter Property="HeaderTemplate">
<Setter.Value>
<DataTemplate>
<DockPanel x:Name="tabHeader" Margin="-5,-1,-5,0" Focusable="True">
<Button x:Name="closeButton"
Width="16"
Height="16"
Margin="20, 10, 10, 10"
Command="{Binding CloseTabCommand}"
CommandParameter="{Binding Title}"
BorderBrush="Transparent"
DockPanel.Dock="Right"
BorderThickness="0">
<Image x:Name="tabIcon" Source="/close.png" Height="16" Margin="0,0,0,0" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Button>
<TextBlock Margin="5, 10, 10, 10" VerticalAlignment="Center" Text="{Binding Title}"/>
</DockPanel>
</DataTemplate>
</Setter.Value>
</Setter>
<Setter Property="Content" Value="{Binding Content}" />
</Style>
</TabControl.ItemContainerStyle>
</TabControl>
</Grid>
</Window>
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
namespace WpfAppTabControl
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
DataContext = new MainViewViewModel();
}
private void OnSelectionChanged(object sender, SelectionChangedEventArgs e)
{
var viewModel = (MainViewViewModel)DataContext;
viewModel.NotifySelectedItemChanged(e.AddedItems);
}
private void OnTabItemLoaded(object sender, RoutedEventArgs e)
{
Keyboard.Focus((UIElement)sender);
}
}
}
ItemViewModel.cs
using Prism.Mvvm;
using System;
using System.Windows.Input;
namespace WpfAppTabControl
{
public class ItemViewModel : BindableBase, IDisposable
{
private string title;
private string content;
public ItemViewModel(ICommand closeTabCommand)
{
CloseTabCommand = closeTabCommand ?? throw new ArgumentNullException(nameof(closeTabCommand));
}
public string Title
{
get => title;
set
{
if (title != value)
{
title = value;
RaisePropertyChanged(title);
}
}
}
public string Content
{
get => content;
set
{
if (content != value)
{
content = value;
RaisePropertyChanged(content);
}
}
}
public ICommand CloseTabCommand
{
get;
private set;
}
public void Dispose()
{
// disposing stuff
}
}
}
MainViewViewModel.cs
using Prism.Commands;
using Prism.Mvvm;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Windows.Input;
namespace WpfAppTabControl
{
public class MainViewViewModel : BindableBase
{
private readonly ObservableCollection<ItemViewModel> itemsToDisplay;
private ItemViewModel activeTabItem;
public MainViewViewModel()
{
itemsToDisplay = new ObservableCollection<ItemViewModel>();
AddTabCommand = new DelegateCommand(AddTab);
}
public IEnumerable<ItemViewModel> ItemsToDisplay => itemsToDisplay;
public ICommand AddTabCommand
{
get;
private set;
}
public ItemViewModel ActiveTabItem
{
get => activeTabItem;
set
{
if (activeTabItem != value)
{
activeTabItem = value;
RaisePropertyChanged();
}
}
}
private void AddTab()
{
var tabCountString = (itemsToDisplay.Count + 1).ToString();
var itemViewModel1 = new ItemViewModel(new DelegateCommand<string>(title => { CloseTab(title); }))
{
Title = "NewTab" + tabCountString,
Content = "Content of " + "NewTab" + tabCountString,
};
itemsToDisplay.Add(itemViewModel1);
ActiveTabItem = itemViewModel1;
}
private void CloseTab(string title)
{
if (string.IsNullOrEmpty(title))
{
return;
}
var tabToClose = itemsToDisplay.FirstOrDefault(viewModel => viewModel.Title == title);
if (tabToClose != null)
{
itemsToDisplay.Remove(tabToClose);
}
}
public void NotifySelectedItemChanged(IList addedItems)
{
if (addedItems.Count > 0)
{
// stuff to do
}
}
}
}