首页 文章

在WPF Tabcontrol Headers 模板中显示SelectedIndex

提问于
浏览
5

我的应用程序中有1 ... n个tabcontrols,具有以下XAML设置:

<TabControl Name="ordersTabControl" ItemsSource="{Binding CoilItems}">
  <TabControl.ItemTemplate>
    <DataTemplate DataType="models:Coil">
      <StackPanel>
        <TextBlock Text="{Binding CoilCode, StringFormat='Coil: {0}'}" />
        <TextBlock Text="{Binding ArticleCode, StringFormat='Auftrag: {0}'}" />
        <TextBlock Text="{Binding RestWeight, StringFormat='Restgewicht: {0} kg'}" />
      </StackPanel>
    </DataTemplate>
  </TabControl.ItemTemplate>
  <TabControl.ContentTemplate>
  [...]
  </TabControl.ContentTemplate>
</TabControl>

打开的选项卡数量在运行时更改 . 现在我想在每个标签中显示索引(即第一个标签显示“订单1”,第二个“订单2”等等)以及每个 Headers 中已有的信息 .

使用DataTemplate时AFAIK我无法通过代码隐藏访问tab-properties,所以在XAML中是否有任何方法可以在tabheader中绑定文本块以显示tabcontrol中该特定选项卡的索引?

我认为应该可以使用RelativeSource和FindAncestors吗?唉,我真的找不到关于这些设置的任何明确的教程(我2天前才开始使用WPF) .

3 回答

  • 2

    我将使用附加属性为您提供解决方案 . 检查代码:

    Attached Properties

    public static class IndexAttachedProperty
    {
    
    
        #region TabItemIndex
    
        public static int GetTabItemIndex(DependencyObject obj)
        {
            return (int) obj.GetValue(TabItemIndexProperty);
        }
    
        public static void SetTabItemIndex(DependencyObject obj, int value)
        {
            obj.SetValue(TabItemIndexProperty, value);
        }
    
        // Using a DependencyProperty as the backing store for TabItemIndex.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TabItemIndexProperty =
            DependencyProperty.RegisterAttached("TabItemIndex", typeof (int), typeof (IndexAttachedProperty),
                                                new PropertyMetadata(-1));
    
    
    
        #endregion
    
        #region TrackTabItemIndex
    
        public static bool GetTrackTabItemIndex(DependencyObject obj)
        {
            return (bool) obj.GetValue(TrackTabItemIndexProperty);
        }
    
        public static void SetTrackTabItemIndex(DependencyObject obj, bool value)
        {
            obj.SetValue(TrackTabItemIndexProperty, value);
        }
    
        // Using a DependencyProperty as the backing store for TrackTabItemIndex.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty TrackTabItemIndexProperty =
            DependencyProperty.RegisterAttached("TrackTabItemIndex", typeof (bool), typeof (IndexAttachedProperty),
                                                new PropertyMetadata(false, TrackTabItemIndexOnPropertyChanged));
    
        private static void TrackTabItemIndexOnPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var tabControl = GetParent(d, p => p is TabControl) as TabControl;
            var tabItem = GetParent(d, p => p is TabItem) as TabItem;
            if (tabControl == null || tabItem == null)
                return;
            if (!(bool)e.NewValue)
                return;
            int index = tabControl.Items.IndexOf(tabItem.DataContext == null ? tabItem : tabItem.DataContext);
            SetTabItemIndex(d, index);
        }
        #endregion
    
    
    
    
    
        public static DependencyObject GetParent(DependencyObject item, Func<DependencyObject, bool> condition)
        {
            if (item == null)
                return null;
            return condition(item) ? item : GetParent(VisualTreeHelper.GetParent(item), condition);
        }
    }
    

    此代码定义了两个附加属性,第一个是设置项是否跟踪包含它的选项卡项索引 . 第二个是索引属性 .

    XAML Sample code:

    <TabControl.ItemTemplate>
                <DataTemplate DataType="{x:Type WpfApplication3:A}">
                    <StackPanel x:Name="tabItemRoot" WpfApplication3:IndexAttachedProperty.TrackTabItemIndex ="True">
                        <TextBlock Text="{Binding Text}"/>
                        <TextBlock Text="{Binding Path=(WpfApplication3:IndexAttachedProperty.TabItemIndex), ElementName=tabItemRoot}"/>
    
                    </StackPanel>
                </DataTemplate>
            </TabControl.ItemTemplate>
    

    上面的代码是使用附加属性的示例 . 您可以轻松地适应您的代码 .

    Result:

    enter image description here

    希望这段代码适合你......

  • 2

    如果您没有将 AlternationCount 属性用于其他目的,则可以通过破解它来获得更简单的解决方案 .

    像这样绑定 AlternationCount

    <TabControl AlternationCount="{Binding Path=Items.Count, RelativeSource={RelativeSource Self}}">
    

    然后在你的ItemTemplate中将TextBlock或其他控件绑定到 AlternationIndex ,就像这样,

    <TextBlock Text="{Binding Path=(ItemsControl.AlternationIndex), RelativeSource={RelativeSource  FindAncestor, AncestorType=TabItem}}" />
    

    通过插入上述绑定的自定义转换器,您可以显示任何所需内容 .

  • 1

    即使你有权访问代码隐藏中的 TabItem 属性,它也不会知道 TabControl 集合中它自己的索引 . 这对于所有_1510575都是如此,并且看起来很烦人,但这是有道理的,因为什么时候任何对象都能告诉你它在集合中的位置是什么?

    但是,只要您可以访问控件的 ItemsCollection 和选项卡的内容,就可以使用IndexOf来完成 . 我们可以在 MultiValueConverter 中执行此操作,以便可以在DataTemplate中完成 .

    Converter code:

    public class ItemsControlIndexConverter : IMultiValueConverter
       {
          public object Convert(object[] values, Type targetType, object parameter, System.Globalization.CultureInfo culture)
          {
             ItemCollection itemCollection = (ItemCollection)values[0];
             return (itemCollection.IndexOf(values[1]) + 1).ToString();
          }
    
          public object[] ConvertBack(object value, Type[] targetTypes, object parameter, System.Globalization.CultureInfo culture)
          {
             throw new NotImplementedException();
          }
       }
    

    TabControl XAML:

    <TabControl ItemsSource="{Binding CoilItems}">
        <TabControl.Resources>
            <local:ItemsControlIndexConverter x:Key="IndexConverter"/>
        </TabControl.Resources>
        <TabControl.ItemTemplate>
             <DataTemplate>
                 <StackPanel Orientation="Horizontal">
                     <TextBlock>
                         <TextBlock.Text>
                             <MultiBinding Converter="{StaticResource IndexConverter}" StringFormat="Order {0}" Mode="OneWay">
                                 <Binding RelativeSource="{RelativeSource AncestorType=TabControl}" Path="Items"/> <!-- First converter index is the ItemsCollection -->
                                 <Binding /> <!-- Second index is the content of this tab -->
                             </MultiBinding>
                         </TextBlock.Text>
                     </TextBlock>
                     <!-- Fill in the rest of the header template -->
                 </StackPanel>
             </DataTemplate>
         </TabControl.ItemTemplate>
     </TabControl>
    

相关问题