标准的WPF Tab控件中是否有选定选项卡更改事件?

114

在WPF中,有没有一种事件可以用来确定TabControl所选标签页发生更改的情况?

我已经尝试使用TabControl.SelectionChanged,但是当标签页内的子项选择发生更改时,它被触发了很多次。

10个回答

145

您需要检查事件的源以隔离您正在寻找的最外层TabControl

我在处理程序中尝试了这个方法,使其正常工作:

void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (e.Source is TabControl)
    {
        // do work when tab is changed
    }
}

3
我本以为这个不起作用,但后来我意识到我在检查sender而不是e.Source - Guillermo Ruffino
5
或者只需添加 e.Handled = true 来防止事件冒泡。 - Brock Hensley
@BrockHensley:这可能会导致您不得不添加许多本来不必要的事件处理程序。 - Ben Voigt

94

如果您将 x:Name 属性设置为每个 TabItem,如下所示:

<TabControl x:Name="MyTab" SelectionChanged="TabControl_SelectionChanged">
    <TabItem x:Name="MyTabItem1" Header="One"/>
    <TabItem x:Name="MyTabItem2" Header="2"/>
    <TabItem x:Name="MyTabItem3" Header="Three"/>
</TabControl>

然后你可以在事件中访问每个 TabItem

private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    if (MyTabItem1.IsSelected)
    // do your stuff
    if (MyTabItem2.IsSelected)
    // do your stuff
    if (MyTabItem3.IsSelected)
    // do your stuff
}

62

如果你只想在选定选项卡时触发某个事件,那么这是正确的方式:

<TabControl>
    <TabItem Selector.Selected="OnTabSelected" />
    <TabItem Selector.Selected="OnTabSelected" />
    <TabItem Selector.Selected="OnTabSelected" />
    <!-- You can also catch the unselected event -->
    <TabItem Selector.Unselected="OnTabUnSelected" />
</TabControl>

在你的代码中

    private void OnTabSelected(object sender, RoutedEventArgs e)
    {
        var tab = sender as TabItem;
        if (tab != null)
        {
            // this tab is selected!
        }
    }

很不幸,尽管这个看起来很好,但我在XAML中无法使用Selected属性,只能使用IsSelected。抱歉。 - PHenry
2
我被纠正了...有点。哎呀!当我在VS中尝试打上述内容时,它会给我红色的波浪线,因此我认为它是错误的。但是当我将其剪切并粘贴后,只是盲目地按下F5,令我惊讶的是,它居然起作用了。嗯?为什么它会以那种方式工作呢? - PHenry
2
我该如何在代码中访问“Selector.Selected”事件,而不是在XAML中? - Ahmed_Faraz
2
@Ahmed_Faraz:someTabItem.AddHandler(Selector.SelectedEvent, .... - Ben Voigt

15

你仍然可以使用那个事件。只需检查发送器参数是否是你实际关心的控件,如果是,则运行事件代码。


8
如果您正在使用MVVM模式,那么使用事件处理程序将是不方便的(并且会破坏该模式)。相反,您可以将每个单独的TabItem的Selector.IsSelected属性绑定到视图模型中的一个依赖属性,然后处理PropertyChanged事件处理程序。这样,您就可以根据PropertyName准确地知道哪个选项卡被选中/取消选中,而且您还可以为每个选项卡设置特殊处理程序。
示例:MainView.xaml
<TabControl>
 <TabItem Header="My tab 1" Selector.IsSelected="{Binding IsMyTab1Selected}"> ... </TabItem>
 <TabItem Header="My tab 2" Selector.IsSelected="{Binding IsMyTab2Selected}"> ... </TabItem>
</TabControl>

示例:MainViewModel.cs
public bool IsMyTab1Selected {
 get { return (bool)GetValue(IsMyTab1SelectedProperty); }
 set { SetValue(IsMyTab1SelectedProperty, value); }
}
public static readonly DependencyProperty IsMyTab1SelectedProperty =
DependencyProperty.Register("IsMyTab1Selected", typeof(bool), typeof(MainViewModel), new PropertyMetadata(true, new PropertyChangedCallback(MyPropertyChanged)));

public bool IsMyTab2Selected {
 get { return (bool)GetValue(IsMyTab2SelectedProperty); }
 set { SetValue(IsMyTab2SelectedProperty, value); }
}
public static readonly DependencyProperty IsMyTab2SelectedProperty =
DependencyProperty.Register("IsMyTab2Selected", typeof(bool), typeof(MainViewModel), new PropertyMetadata(false, new PropertyChangedCallback(MyPropertyChanged)));

private void MyPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) {
 if (e.Property.Name == "IsMyTab1Selected") {
  // stuff to do
 } else if (e.Property.Name == "IsMyTab2Selected") {
  // stuff to do
 }
}

如果您的MainViewModel实现了INotifyPropertyChanged而不是继承自DependencyObject,那么请使用以下代码替换:

示例:MainViewModel.cs

public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName) {
 PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

public MainViewModel() {
 PropertyChanged += handlePropertyChanged;
}

public bool IsMyTab1Selected {
 get { return _IsMyTab1Selected ; }
 set {
  if (value != _IsMyTab1Selected ) {
   _IsMyTab1Selected = value;
   OnPropertyChanged("IsMyTab1Selected ");
  }
 }
}
private bool _IsMyTab1Selected = false;

public bool IsMyTab2Selected {
 get { return _IsMyTab2Selected ; }
 set {
  if (value != _IsMyTab2Selected ) {
   _IsMyTab2Selected = value;
   OnPropertyChanged("IsMyTab2Selected ");
  }
 }
}
private bool _IsMyTab2Selected = false;

private void handlePropertyChanged(object sender, PropertyChangedEventArgs e) {
 if (e.PropertyName == "IsMyTab1Selected") {
  // stuff to do
 } else if (e.PropertyName == "IsMyTab2Selected") {
  // stuff to do
 }
}

4

生成的事件会一直冒泡到处理它的位置。

以下的xaml部分在选中ListView中的项更改时触发 ui_A_Changed 后立即触发ui_Tab_Changed,而不管 TabControl 中的 TabItem 是否更改。

<TabControl SelectionChanged="ui_Tab_Changed">
  <TabItem>
    <ListView SelectionChanged="ui_A_Changed" />
  </TabItem>
  <TabItem>
    <ListView SelectionChanged="ui_B_Changed" />
  </TabItem>
</TabControl>

我们需要在 ui_A_Changed (以及 ui_B_Changed 等等) 中消费事件:
private void ui_A_Changed(object sender, SelectionChangedEventArgs e) {
  // do what you need to do
  ...
  // then consume the event
  e.Handled = true;
}

4

那就是正确的事件。也许它没有正确连接?

<TabControl SelectionChanged="TabControl_SelectionChanged">
    <TabItem Header="One"/>
    <TabItem Header="2"/>
    <TabItem Header="Three"/>
</TabControl>

在代码后端....
private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    int i = 34;
}

如果我在 i = 34 这一行设置断点,那么它只会在我切换标签页时才中断,即使标签页有子元素并且其中一个被选中。


在选项卡中放置一个网格,选择网格行将冒泡到选项卡选中事件,如果在到达那里之前未处理,则会触发该事件。 - Paul Swetz

2
这段代码似乎可以正常工作:
    private void TabControl_SelectionChanged(object sender, SelectionChangedEventArgs e)
    {
        TabItem selectedTab = e.AddedItems[0] as TabItem;  // Gets selected tab

        if (selectedTab.Name == "Tab1")
        {
            // Do work Tab1
        }
        else if (selectedTab.Name == "Tab2")
        {
            // Do work Tab2
        }
    }

0

如果你正在做mvvm,你也可以通过绑定TabControl的SelectedIndex属性来实现这一点:

<TabControl SelectedIndex="{Binding SelectedTabIndex}"

当属性更新时,您将收到更改的通知,并立即获得所选TabItem的索引。


-2

如果有人使用WPF Modern UI,他们无法使用OnTabSelected事件,但是他们可以使用SelectedSourceChanged事件。

就像这样

<mui:ModernTab Layout="Tab" SelectedSourceChanged="ModernTab_SelectedSourceChanged" Background="Blue" AllowDrop="True" Name="tabcontroller" >

C# 代码是

private void ModernTab_SelectedSourceChanged(object sender, SourceEventArgs e)
    {
          var links = ((ModernTab)sender).Links;

          var link = this.tabcontroller.Links.FirstOrDefault(l => l.Source == e.Source);

          if (link != null) {
              var index = this.tabcontroller.Links.IndexOf(link);
              MessageBox.Show(index.ToString());
          }            
    }

3
使用第三方的论点从来不是解决问题的方法,应该强烈反对。 - Steven Borges
@steven,我写了这个针对WPF MUI的,并不是答案,但这可能会成为WPF MUI用户的答案。这就是为什么我把它作为一个答案的原因。谢谢。 - Sandun Harshana

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接