【问题标题】:Get visible TabItems in TabControl在 TabControl 中获取可见的 TabItems
【发布时间】:2021-10-27 18:42:07
【问题描述】:

我有一个带有可滚动 TabItems/Header 的 TabControl。我的 TabControl ItemsSources 绑定到 ObservableCollection。有什么方法可以在 TabControl 中获取可见的 TabItems。

假设我有 20 个 TabItems,只有 7 个是可见的,或者 10 个或更多,具体取决于用户执行的操作类型(例如缩小窗口)。如何以编程方式检索可见的 TabItems ?

这是 XAML 代码:

<TabControl x:Name="tabControl"
                  ItemsSource="{Binding Data}" 
                  ScrollViewer.CanContentScroll="True"
                  Width="440" 
                  Height="350"
                  TabStripPlacement="Top" 
                  Background="LightGray" 
                  BorderBrush="Blue">
        <TabControl.Template>
          <ControlTemplate TargetType="TabControl">
            <Grid>
              <Grid.RowDefinitions>
                <RowDefinition Height="Auto" />
                <RowDefinition />
              </Grid.RowDefinitions>
              <ScrollViewer HorizontalScrollBarVisibility="Auto"  VerticalScrollBarVisibility="Hidden" >
                <TabPanel x:Name="HeaderPanel"
                          Panel.ZIndex ="1" 
                          KeyboardNavigation.TabIndex="1"
                          Grid.Column="0"
                          Grid.Row="0"
                          Margin="2,2,2,0"
                          IsItemsHost="true" />
              </ScrollViewer>
              <ContentPresenter x:Name="PART_SelectedContentHost"
                                SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"
                                Margin="{TemplateBinding Padding}"
                                ContentSource="SelectedContent" Grid.Row="1" />
            </Grid>
          </ControlTemplate>
        </TabControl.Template>
      </TabControl>

      <Button x:Name="button" 
              Content="Add Items" 
              Margin="5" 
              HorizontalAlignment="Center" 
              VerticalAlignment="Center"
              Width="120" 
              Click="Button_Click" />

      <Button x:Name="button2" 
              Content="TabItems in View" 
              Margin="5" 
              HorizontalAlignment="Center" 
              VerticalAlignment="Center"
              Width="120" 
              Click="Button_Click2" />

这是我的代码:

public partial class MainWindow : Window
  {
    private static int counter = 0;
    public List<TabItem> visibleItems = new List<TabItem>();
    public ObservableCollection<string> Data {  get;  set; }
    public MainWindow()
    {
      InitializeComponent();
      this.DataContext = this;

      this.Data = new ObservableCollection<string>()
      {
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter,
        "item" + ++counter
      };
    }

    
    private void Button_Click( object sender, RoutedEventArgs e )
    {
      // add tab item and reduce the TabControl window:
      this.Data.Add( "newItem" + ++counter );
      
      this.tabControl.Width = 330d;
    }

    private void Button_Click2( object sender, RoutedEventArgs e )
    {
      visibleItems = new List<TabItem>();
      foreach( var item in tabControl.Items )
      {
        TabItem tabItem = this.tabControl.ItemContainerGenerator.ContainerFromItem( item ) as TabItem;
        if( tabItem != null && tabItem.Visibility == Visibility.Visible )
        {
          visibleItems.Add( tabItem );
        }
      }

      Debug.WriteLine( $"{visibleItems.Count}" ); // always return 20 ...
    }
  }

Button_Click2 事件处理程序是我实现检索可见 TabItems 的逻辑的地方。但它不起作用。它总是返回我的项目来源总数。

【问题讨论】:

    标签: c# wpf tabcontrol


    【解决方案1】:

    您必须迭代项目容器并累积项目宽度。然后获取TabPanel的ScrollViewer,根据ScrollViewer.HorizontalOffset(起始位置)和ScrollViewer.ViewportWidth(确定实际可见项)收集可见项。
    关键是滚动查看器的宽度是以 DIP 而不是项目来衡量的。当您可以确保所有项目容器具有相同的宽度时,该算法会更加精确。

    您可以在 How to: Find DataTemplate-Generated Elements 找到 FindVisualChild 的一个实现。

    private void Button_Click2(object sender, RoutedEventArgs e)
    {
      var scrollViewer = FindVisualChild<ScrollViewer>(this.tabControl);
      if (scrollViewer != null)
      {
        int startIndex = GetFirstVisibleItemIndex(scrollViewer.HorizontalOffset);
        double totalItemContainerWidth = 0;
        List<(object Item, TabItem ItemContainer)> visibleItems = GetVisibleItems(startIndex, scrollViewer.ViewportWidth);
      }
    }
    
    private int GetFirstVisibleItemIndex(double horizontalScrollViewerOffset)
    {
      double totalItemContainerWidth = 0;
      int itemIndex = 0;
      while (totalItemContainerWidth < horizontalScrollViewerOffset)
      {
        var hiddenItemContainer = this.tabControl.ItemContainerGenerator.ContainerFromIndex(++itemIndex) as FrameworkElement;
        totalItemContainerWidth += hiddenItemContainer.ActualWidth;
      }
    
      return itemIndex;
    }
    
    // Returns a collection of tuples (item and item container tuples)
    private List<(object Item, TabItem ItemContainer)> GetVisibleItems(int startIndex, double viewportWidth)
    {
      var visibleItems = new List<(object Item, TabItem ItemContainer)>();
      double totalItemContainerWidth = 0;
      for (int currentVisibleItemIndex = startIndex; currentVisibleItemIndex < this.tabControl.Items.Count; currentVisibleItemIndex++)
      {
        var visibleItemContainer = this.tabControl.ItemContainerGenerator.ContainerFromIndex(currentVisibleItemIndex) as TabItem;
        totalItemContainerWidth += visibleItemContainer.ActualWidth;
        if (totalItemContainerWidth > viewportWidth + visibleItemContainer.ActualWidth)
        {
          break;
        }
    
        object visibleItem = this.tabControl.Items[currentVisibleItemIndex];
        visibleItems.Add((visibleItem, visibleItemContainer));
      }
    
      return visibleItems;
    }
    

    【讨论】:

      猜你喜欢
      • 2012-01-20
      • 1970-01-01
      • 1970-01-01
      • 2012-01-29
      • 1970-01-01
      • 1970-01-01
      • 2011-02-18
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多