如何关注WPF TabControl新添加的TabItem?

2024-01-25

我面临一个问题,我需要能够真正集中精力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

按左侧的“添加选项卡”按钮后,一个新选项卡将添加到ObservableCollection然后反映在选项卡控件中的新选项卡项中。

我尝试将新选项卡的重点放在:

  • Set the SelectedItem of the TabControl添加新项目后(参见下面的代码)
  • Keyboard.Focus((UIElement)sender)在选项卡项加载事件中(参见下面的代码)
  • 通过设置FocusManager.FocusedElement="{Binding ElementName=tabHeader}"在 XAML 中(参见下面的代码)

这些尝试似乎都不起作用。

期望的行为新添加的选项卡项目实际上会获得焦点(就像我会按TABkey) 看起来像这样:

为了创建这个图像,我按下了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
         }
      }
   }
}

有同样的问题。将新的 tabitem 添加到 tabcontrol:示例TabItem newtabitem = new TabItem然后使用newtabitem.Focus()。这会将焦点移至添加的选项卡。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何关注WPF TabControl新添加的TabItem? 的相关文章

  • WPF 中 ToggleButton 的 IsChecked 属性的 OneWay 绑定

    我有一个ToggleButton以其IsChecked使用 OneWay 绑定将属性绑定到属性
  • tabControl/tabitem 刷新困难

    我有一个带有 maintabWindow 和几个 tabitem 的 WPF 窗口 它通常工作正常 布局是这样的 但是当我之前添加以下窗口时 结果是这样的 所以问题与 tabControl tabItem 刷新有关 这是相当明显的 但更重要
  • 使用 TemplateColumns 将 WPF DataGrid 绑定到 DataTable

    我已经尝试了一切但一无所获 所以我希望有人能给我一个顿悟的时刻 我根本无法获得成功提取数据网格中数据的绑定 我有一个包含 MyDataType 的多列的 DataTable public class MyData string nameDa
  • 使用MVVM Light的Messenger在视图模型之间传递值

    有人可以帮我解释一下 MVVM Light 的 Messenger 吗 我正在阅读 StackOverflow 上的一篇文章 MVVM 在视图模型之间传递值 https stackoverflow com questions 6392854
  • WPF 组合框如果只有 1 项则自动选择

    我有一个组合框 我绑定到一个可观察的集合 它会发生变化 根据选择的公司 并且大量公司将有一个帐户 项目 因此我想知道制作组合框的最佳方法是什么如果 ItemsSource 中只有 1 个项目 则设置 SelectedItem 否则将其保留为
  • WPF DataGrid 绑定 DataGridCell 内容

    希望这将是一个非常简单的答案 我认为我只是没有看到众所周知的树木 我有一个 DataGridCell 样式 我想将单元格的内容绑定到图像的源属性 这是我目前使用的 XAML
  • WPF 元素宿主内存泄漏

    我在 Windows 窗体上使用元素主机时遇到奇怪的内存泄漏 我有一个主窗体 它打开另一个窗体 该窗体上只有 elementhost 控件 此时 它没有 wpf 控件子控件 只能打开 1 个主机表单 每次我打开窗体时 应用程序内存都会增加2
  • 我可以禁用特定控件的键盘输入吗?

    是否可以禁用控件的键盘输入 例如一个ListView 我怎么做 我尝试过覆盖KeyUp KeyDown事件 但显然不是这样的 IsEnabled是一个很好的解决方案 但是我只想禁用键盘交互并保持鼠标交互不变 处理KeyDown事件来得太晚了
  • 将 WPF 快捷键绑定到 ViewModel 中的命令

    我有一个使用 MVVM 模式的 WPF 应用程序 将按钮连接到 VM 非常简单 因为它们实现了 ICommand 我有一个工作原理类似的上下文菜单 下一步是为上下文菜单创建快捷键 我不知道如何让快捷键调用命令 这是一个例子
  • 使用 INotifyPropertyChanged

    有人可以解释一下为什么在 wpf 中使用绑定时需要使用 INotifyPropertyChanged 的 实现吗 我可以在不实现此接口的情况下绑定属性吗 例如我有代码 public class StudentData INotifyProp
  • 该组件没有由 uri 标识的资源

    我想创建一个通用数据网格以在我的所有视图 用户控件上使用 这是我的结构 Class Library called Core Class called ViewBase public class ViewBase UserControl pu
  • 使 DataTemplate 可混合

    如何为 ViewModel 制作可混合的数据模板 可在表达式混合中设计 当我转到资源并尝试直接编辑数据模板时 我在绘图板上看到的只是一个空白矩形 这是因为 DataTemplate 没有绑定到任何东西 当然 我可以创建一个 UserCont
  • 比较运算符性能 <= 与 !=

    让我们首先声明代码可读性胜过微优化 我们应该将其留给编译器 这只是一个奇怪的案例 具体细节似乎与一般建议相比很有趣 因此 我在搞素数生成器函数 并提出了一种奇怪的行为 其中 人们建议效率最高 实际上效率最低 而 C private stat
  • 窗口关闭后仍在调用方法

    首先我不知道这是不是一个愚蠢的问题 我有这样的场景 首先我有一个主窗口 public MainWindow InitializeComponent dt is a System Windows Threading DispatcherTim
  • WPF DataGrid 多选

    我读过几篇关于这个主题的文章 但很多都是来自 VS 或框架的早期版本 我想做的是从 dataGrid 中选择多行并将这些行返回到绑定的可观察集合中 我尝试创建一个属性 类型 并将其添加到可观察集合中 它适用于单个记录 但代码永远不会触发多个
  • 根据属性的类型使用文本框或复选框

    如果我有这样的结构 public class Parent public string Name get set public List
  • 在 WPF 中使用 ReactiveUI 提供长时间运行命令反馈的正确方法

    我有一个 C WPF NET 4 5 应用程序 用户将用它来打开某些文件 然后 应用程序将经历很多动作 读取文件 通过许多插件和解析器传递它 这些文件可能相当大 gt 100MB 因此这可能需要一段时间 我想让用户了解 UI 中发生的情况
  • 如何从代码隐藏访问ListBox动态创建的项目的属性?

    XAML
  • WPF:Prism 对于小型应用程序来说是不是太过分了?

    如果我不将我的应用程序分成不同的模块 否则我会认为 Prism 确实是可行的方法 我应该使用 Prism 吗 我知道 Prism 提供了一个方便的实现ICommand 我可以自己在一页代码中完成 并为我们提供IEventAggregator
  • WPF - 如何从 DataGridRow 获取单元格?

    我有一个具有交替行背景颜色的数据绑定 DataGrid 我想根据单元格包含的数据对单元格进行不同的着色 我已经尝试过该线程建议的解决方案 http wpf codeplex com Thread View aspx ThreadId 511

随机推荐