Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show SelectedIndex in WPF Tabcontrol header template

I have 1...n tabcontrols in my application, with the following XAML setup:

<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>

The amount of open tabs changes at runtime. Now I'd like to show an index in each tab (i.e. the first tab shows "Order 1", the second "Order 2" and so on) in addition to the information already in each header.

AFAIK when using DataTemplate I can't access the tab-properties through the code-behind, so is there any way in XAML to bind a textblock inside a tabheader to show the Index of that specific tab in the tabcontrol?

I think it should be possible with RelativeSource and FindAncestors? Alas I couldn't really find any clear tutorial on those settings (and I only started using WPF 2 days ago).

like image 897
Aether McLoud Avatar asked Mar 21 '13 16:03

Aether McLoud


1 Answers

I'm going to give you a solution using attached properties. Check the code:

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);
    }
}

This code define two attached properties, the first one is to set if an item tracks the the tab item index in wich it is contained. The second one is the index property.

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>

The above code is an example of using the attached property. You may adapt to your code easy.

Result:

enter image description here

Hope this code works for you...

like image 192
Raúl Otaño Avatar answered Oct 13 '22 07:10

Raúl Otaño