如何知道动态创建的 TabItem 的索引

Posted

技术标签:

【中文标题】如何知道动态创建的 TabItem 的索引【英文标题】:How to know the index of dynamically created TabItem 【发布时间】:2014-10-29 07:36:49 【问题描述】:

我在 xaml 中有这样的:

<controls:TabControl Grid.Row="0" BorderThickness="0" Background="White" 
                         ItemsSource="Binding TabList, Mode=TwoWay, Converter=StaticResource TabConverter"                        
                         SelectedItem="Binding CurrentItem, Mode=TwoWay"/>

在视图模型中我有:

 private TabItem currentItem;
    public TabItem CurrentItem
    
        get  return currentItem; 
        set 
        
            //currentItem.Content               
            currentItem = value;
          int index = currentItem.TabIndex;  //IT GIVES STRANgE INDEX ON DEBUGGING ob Tab click (like 22255788586)                   
            OnPropertyChanged("CurrentItem");
        
    

但是这个 TabList(在 xaml 中)是这样动态生成的:

public void AddVersion(ProgramVersion pv) //it creates the TabList
        
            if (pv != null)
                           
                if (index == -1)
                                      
                    TabList.Add(new ProgramVersionItemViewModel(pv));                    
                    OnPropertyChanged("TabList");                
                                
            
        

每次按下按钮我都会调用函数 AddVersion(version);它会添加到 TabList 中。

问题是当我单击 CurrentItem(动态创建的 TabItems (TabList) 数量)时,它会给出非常大的奇怪地址(如 222557456)。

我获取当前项目索引的方法是错误的吗? (int index = currentItem.TabIndex;) ?

【问题讨论】:

TabIndex 不是选项卡的索引 - 它用于在按 TAB 键在控件之间循环时对控件进行排序。 TabIndex 并不意味着 TabControl 内的项目索引。由于您有一个 ViewModel 列表,SelectedItem 可能不会返回 TabItem,它应该是指绑定到当前TabItem的ViewModel。所以你可以试试这个TabList.IndexOf(CurrentItem) @Luaan 那么如何在这里解决该解决方案以了解在 CurrentItem 集合内单击的当前项目的索引? @Claw 执行 siad 给出的操作:错误参数 1:无法从 'System.Windows.Controls.TabItem' 转换为 'ViewModel.ProgramVersionItemViewModel' 您只需将Tag 属性设置为pv,然后当您想阅读它时,只需进行显式转换-(ProgramVersion)currentItem.Tag 【参考方案1】:

说实话,这是一种方法。这里可能是一个更好的解决方案:

    private void Button1_Click(object sender, RoutedEventArgs e)
    
        TabControl1.Items.Add(new TabItem()  TabIndex = 0, Header = "Tab 0" );
        TabControl1.Items.Add(new TabItem()  TabIndex = 1, Header = "Tab 1" );
        TabControl1.Items.Add(new TabItem()  TabIndex = 2, Header = "Tab 2" );
        TabControl1.Items.Add(new TabItem()  TabIndex = 3, Header = "Tab 3" );
    

请注意,我们正在添加 new TabItem() 并为其提供标签索引和标题。使用这种方法更加动态和可靠。

因此,在您的示例中,您可能会执行以下操作:

        if (pv != null)
        
            if (index == -1)
            
                TabList.Add(new TabItem()  TabIndex = <EnumeratedValue>, Header = "Tab " + <EnumeratedValue>.ToString());
            
        

【讨论】:

如果您使用的是 MVVM 方法,由于它们绑定 CurrentItem 的方式,OP 可能会使用这种方法,这不是一个更好的解决方案。此外,TabIndex 不是选项卡的索引(正如其他评论者已经指定的那样),而是用户通过它们进行选项卡时使用的控件的顺序。选项卡上没有可用的索引,父容器具有所选项目的索引 (SelectedIndex) iirc。 正确,其他人也发表了同样的评论。虽然如果您是动态添加和删除选项卡,为什么不使用 tabindex 呢?如果最终用户希望通过选项卡进行 TAB,您的订单将始终得到明确定义。 因为 WPF/SL 会根据控件在页面上的位置自动设置标签索引。除非您遇到严重问题或者您想将其设置为不直观的顺序,否则您不需要明确设置它 Charleh - 一开始我不相信你,然后我试了一下。我的立场是正确的。【参考方案2】:

7 年后仍然没有令人满意的答案..

这是一个快速的虚拟修复,只要您使用 TabItem 实例来填充父 TabControl 并且不要弄乱复杂的转换器。

将下面的代码放在实用程序静态(内部)类中。添加适当的引用,如using System.Windows.Controls(或者直接在System.Windows.Controls命名空间下创建静态类)

/// <summary>
/// Gets the current index of the Tab under a TabControl.
/// </summary>
/// <param name="tabItem">This TabItem.</param>
/// <param name="defaultReturn">A default value to return if no index could be retrieved.</param>
/// <returns>The sequential index of the tab.</returns>
public static Int32 GetIndex(this TabItem tabItem, Int32 defaultReturn = 0) 

    if (tabItem == null) 
        throw new ArgumentNullException("tabItem", "TabItem is null.");
    if (tabItem.Parent is TabControl) 
    
        TabControl parent = (TabControl)tabItem.Parent;
        int i = 0;

        foreach (var tab in parent.Items) 
        
            if (ReferenceEquals(tab, tabItem)) 
                return i;

            i = i + 1;
        
    

    return defaultReturn;

那么你就可以使用它了:

// Select the latest created tab...
Dispatcher.BeginInvoke((Action)(() => TheTabControl.SelectedIndex = CurrentItem.GetIndex(0)));

您可以在相同的基础上创建其他扩展方法,例如 TabControl.GetLastTab() 或 TabItem.SetIndex(0),但这超出了本主题的范围。

【讨论】:

以上是关于如何知道动态创建的 TabItem 的索引的主要内容,如果未能解决你的问题,请参考以下文章

单击中键关闭TabItem

es 创建动态索引(二)

ES 索引模板和动态模板

如何在ASP中动态为用户创建数据表

es 创建动态索引(一)

如何在工作表中动态创建具有列数的数组,以删除多列中的重复项