Click here to Skip to main content
15,886,110 members
Articles / Desktop Programming / WPF

An Extended WPF TabControl

Rate me:
Please Sign up or sign in to vote.
4.78/5 (58 votes)
5 Apr 2009CPOL3 min read 321.8K   10.9K   151  
Altering the WPF TabControl to show a single row of scrolling TabItems
using System;
using System.Collections;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using System.Windows.Data;
using System.Windows.Media;
using System.Windows.Input;

namespace Wpf.Controls
{
    [TemplatePart(Name = "PART_DropDown", Type = typeof(ToggleButton))]
    [TemplatePart(Name = "PART_RepeatLeft", Type = typeof(RepeatButton))]
    [TemplatePart(Name = "PART_RepeatRight", Type = typeof(RepeatButton))]
    [TemplatePart(Name = "PART_NewTabButton", Type = typeof(ButtonBase))]
    [TemplatePart(Name = "PART_ScrollViewer", Type = typeof(ScrollViewer))]
    public class TabControl : System.Windows.Controls.TabControl
    {
        // public Events
        #region Events

        public event EventHandler<CancelEventArgs> TabItemAdding;
        public event EventHandler<TabItemEventArgs> TabItemAdded;
        public event EventHandler<TabItemCancelEventArgs> TabItemClosing;
        public event EventHandler<TabItemEventArgs> TabItemClosed;
        public event EventHandler<NewTabItemEventArgs> NewTabItem;

        #endregion

        // TemplatePart controls
        private ToggleButton _toggleButton;
        private ButtonBase _addNewButton;

        static TabControl()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TabControl), new FrameworkPropertyMetadata(typeof(TabControl)));
            TabStripPlacementProperty.AddOwner(typeof(TabControl), new FrameworkPropertyMetadata(Dock.Top, new PropertyChangedCallback(OnTabStripPlacementChanged)));
        }

        public TabControl()
        {
            Loaded +=
                delegate
                {
                    SetAddNewButtonVisibility();
                    SetTabItemsCloseButtonVisibility();
                    IsUsingItemsSource = BindingOperations.IsDataBound(this, ItemsSourceProperty);

                    if (IsUsingItemsSource && IsFixedSize)
                        AllowAddNew = AllowDelete = false;
                };
        }

        #region Properties

        private bool IsFixedSize
        {
            get
            {
                IEnumerable items = GetItems();
                return items as IList == null || (items as IList).IsFixedSize;
            }
        }

        #endregion

        #region Dependancy properties

        public bool IsUsingItemsSource
        {
            get { return (bool)GetValue(IsUsingItemsSourceProperty); }
            private set { SetValue(IsUsingItemsSourcePropertyKey, value); }
        }

        public static readonly DependencyPropertyKey IsUsingItemsSourcePropertyKey =
            DependencyProperty.RegisterReadOnly("IsUsingItemsSource", typeof(bool), typeof(TabControl), new UIPropertyMetadata(false));

        public static readonly DependencyProperty IsUsingItemsSourceProperty = IsUsingItemsSourcePropertyKey.DependencyProperty;

        #region Brushes

        public Brush TabItemNormalBackground
        {
            get { return (Brush)GetValue(TabItemNormalBackgroundProperty); }
            set { SetValue(TabItemNormalBackgroundProperty, value); }
        }
        public static readonly DependencyProperty TabItemNormalBackgroundProperty = DependencyProperty.Register("TabItemNormalBackground", typeof(Brush), typeof(TabControl), new UIPropertyMetadata(null));

        public Brush TabItemMouseOverBackground
        {
            get { return (Brush)GetValue(TabItemMouseOverBackgroundProperty); }
            set { SetValue(TabItemMouseOverBackgroundProperty, value); }
        }
        public static readonly DependencyProperty TabItemMouseOverBackgroundProperty = DependencyProperty.Register("TabItemMouseOverBackground", typeof(Brush), typeof(TabControl), new UIPropertyMetadata(null));

        public Brush TabItemSelectedBackground
        {
            get { return (Brush)GetValue(TabItemSelectedBackgroundProperty); }
            set { SetValue(TabItemSelectedBackgroundProperty, value); }
        }
        public static readonly DependencyProperty TabItemSelectedBackgroundProperty = DependencyProperty.Register("TabItemSelectedBackground", typeof(Brush), typeof(TabControl), new UIPropertyMetadata(null));




        #endregion

        /*
         * Based on the whether the ControlTemplate implements the NewTab button and Close Buttons determines the functionality of the AllowAddNew & AllowDelete properties
         * If they are in the control template, then the visibility of the AddNew & Header buttons are bound to these properties
         * 
        */
        /// <summary>
        /// Allow the User to Add New TabItems
        /// </summary>
        public bool AllowAddNew
        {
            get { return (bool)GetValue(AllowAddNewProperty); }
            set { SetValue(AllowAddNewProperty, value); }
        }
        public static readonly DependencyProperty AllowAddNewProperty = DependencyProperty.Register("AllowAddNew", typeof(bool), typeof(TabControl),
            new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnAllowAddNewChanged), OnCoerceAllowAddNewCallback));

        private static void OnAllowAddNewChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((TabControl)d).SetAddNewButtonVisibility();
        }

        private static object OnCoerceAllowAddNewCallback(DependencyObject d, object basevalue)
        {
            return ((TabControl)d).OnCoerceAllowAddNewCallback(basevalue);
        }

        private object OnCoerceAllowAddNewCallback(object basevalue)
        {
            if (ItemsSource != null)
            {
                IList list = ItemsSource as IList;
                if (list != null)
                {
                    if (list.IsFixedSize)
                        return false;
                    return basevalue;
                }
                return false;
            }
            return basevalue;
        }

        /// <summary>
        /// Allow the User to Delete TabItems
        /// </summary>
        public bool AllowDelete
        {
            get { return (bool)GetValue(AllowDeleteProperty); }
            set { SetValue(AllowDeleteProperty, value); }
        }
        public static readonly DependencyProperty AllowDeleteProperty = DependencyProperty.Register("AllowDelete", typeof(bool), typeof(TabControl),
            new FrameworkPropertyMetadata(true, new PropertyChangedCallback(OnAllowDeleteChanged), OnCoerceAllowDeleteNewCallback));

        private static void OnAllowDeleteChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TabControl tc = (TabControl)d;
            tc.SetTabItemsCloseButtonVisibility();
        }

        private static object OnCoerceAllowDeleteNewCallback(DependencyObject d, object basevalue)
        {
            return ((TabControl)d).OnCoerceAllowDeleteCallback(basevalue);
        }
        private object OnCoerceAllowDeleteCallback(object basevalue)
        {
            if (ItemsSource != null)
            {
                IList list = ItemsSource as IList;
                if (list != null)
                {
                    if (list.IsFixedSize)
                        return false;
                    return basevalue;
                }
                return false;
            }
            return basevalue;
        }

        /// <summary>
        /// Set new Header as the current selection
        /// </summary>
        public bool SelectNewTabOnCreate
        {
            get { return (bool)GetValue(SelectNewTabOnCreateProperty); }
            set { SetValue(SelectNewTabOnCreateProperty, value); }
        }
        public static readonly DependencyProperty SelectNewTabOnCreateProperty = DependencyProperty.Register("SelectNewTabOnCreate", typeof(bool), typeof(TabControl), new UIPropertyMetadata(true));


        /// <summary>
        /// Determines where new TabItems are added to the TabControl
        /// </summary>
        /// <remarks>
        ///     Set to true (default) to add all new Tabs to the end of the TabControl
        ///     Set to False to insert new tabs after the current selection
        /// </remarks>
        public bool AddNewTabToEnd
        {
            get { return (bool)GetValue(AddNewTabToEndProperty); }
            set { SetValue(AddNewTabToEndProperty, value); }
        }
        public static readonly DependencyProperty AddNewTabToEndProperty = DependencyProperty.Register("AddNewTabToEnd", typeof(bool), typeof(TabControl), new UIPropertyMetadata(true));

        /// <summary>
        /// defines the Minimum width of a Header
        /// </summary>
        [DefaultValue(20.0)]
        [Category("Layout")]
        [Description("Gets or Sets the minimum Width Constraint shared by all Items in the Control, individual child elements MinWidth property will overide this property")]
        public double TabItemMinWidth
        {
            get { return (double)GetValue(TabItemMinWidthProperty); }
            set { SetValue(TabItemMinWidthProperty, value); }
        }
        public static readonly DependencyProperty TabItemMinWidthProperty = DependencyProperty.Register("TabItemMinWidth", typeof(double), typeof(TabControl),
            new FrameworkPropertyMetadata(20.0, new PropertyChangedCallback(OnMinMaxChanged), CoerceMinWidth));

        private static object CoerceMinWidth(DependencyObject d, object value)
        {
            TabControl tc = (TabControl)d;
            double newValue = (double)value;

            if (newValue > tc.TabItemMaxWidth)
                return tc.TabItemMaxWidth;

            return (newValue > 0 ? newValue : 0);
        }

        /// <summary>
        /// defines the Minimum height of a Header
        /// </summary>
        [DefaultValue(20.0)]
        [Category("Layout")]
        [Description("Gets or Sets the minimum Height Constraint shared by all Items in the Control, individual child elements MinHeight property will override this value")]
        public double TabItemMinHeight
        {
            get { return (double)GetValue(TabItemMinHeightProperty); }
            set { SetValue(TabItemMinHeightProperty, value); }
        }
        public static readonly DependencyProperty TabItemMinHeightProperty = DependencyProperty.Register("TabItemMinHeight", typeof(double), typeof(TabControl),
            new FrameworkPropertyMetadata(20.0, new PropertyChangedCallback(OnMinMaxChanged), CoerceMinHeight));

        private static object CoerceMinHeight(DependencyObject d, object value)
        {
            TabControl tc = (TabControl)d;
            double newValue = (double)value;

            if (newValue > tc.TabItemMaxHeight)
                return tc.TabItemMaxHeight;

            return (newValue > 0 ? newValue : 0);
        }

        /// <summary>
        /// defines the Maximum width of a Header
        /// </summary>
        [DefaultValue(double.PositiveInfinity)]
        [Category("Layout")]
        [Description("Gets or Sets the maximum width Constraint shared by all Items in the Control, individual child elements MaxWidth property will override this value")]
        public double TabItemMaxWidth
        {
            get { return (double)GetValue(TabItemMaxWidthProperty); }
            set { SetValue(TabItemMaxWidthProperty, value); }
        }
        public static readonly DependencyProperty TabItemMaxWidthProperty = DependencyProperty.Register("TabItemMaxWidth", typeof(double), typeof(TabControl),
            new FrameworkPropertyMetadata(double.PositiveInfinity, new PropertyChangedCallback(OnMinMaxChanged), CoerceMaxWidth));

        private static object CoerceMaxWidth(DependencyObject d, object value)
        {
            TabControl tc = (TabControl)d;
            double newValue = (double)value;

            if (newValue < tc.TabItemMinWidth)
                return tc.TabItemMinWidth;

            return newValue;
        }

        /// <summary>
        /// defines the Maximum width of a Header
        /// </summary>
        [DefaultValue(double.PositiveInfinity)]
        [Category("Layout")]
        [Description("Gets or Sets the maximum height Constraint shared by all Items in the Control, individual child elements MaxHeight property will override this value")]
        public double TabItemMaxHeight
        {
            get { return (double)GetValue(TabItemMaxHeightProperty); }
            set { SetValue(TabItemMaxHeightProperty, value); }
        }
        public static readonly DependencyProperty TabItemMaxHeightProperty = DependencyProperty.Register("TabItemMaxHeight", typeof(double), typeof(TabControl),
            new FrameworkPropertyMetadata(double.PositiveInfinity, new PropertyChangedCallback(OnMinMaxChanged), CoerceMaxHeight));

        private static object CoerceMaxHeight(DependencyObject d, object value)
        {
            TabControl tc = (TabControl)d;
            double newValue = (double)value;

            if (newValue < tc.TabItemMinHeight)
                return tc.TabItemMinHeight;

            return newValue;
        }

        /// <summary>
        /// OnMinMaxChanged callback responds to any of the Min/Max dependancy properties changing
        /// </summary>
        /// <param name="d"></param>
        /// <param name="e"></param>
        private static void OnMinMaxChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TabControl tc = (TabControl)d;
            if (tc.Template == null) return;

            foreach (TabItem child in tc.InternalChildren())
            {
                if (child != null)
                    child.Dimension = null;
            }


            //            var tabsCount = tc.GetTabsCount();
            //            for (int i = 0; i < tabsCount; i++)
            //            {
            //                Header ti = tc.GetTabItem(i);
            //                if (ti != null)
            //                    ti.Dimension = null;
            //            }

            TabPanel tp = Helper.FindVirtualizingTabPanel(tc);
            if (tp != null)
                tp.InvalidateMeasure();
        }

        /// <summary>
        /// OnTabStripPlacementChanged property callback
        /// </summary>
        /// <remarks>
        ///     We need to supplement the base implementation with this method as the base method does not work when
        ///     we are using virtualization in the tabpanel, it only updates visible items
        /// </remarks>
        private static void OnTabStripPlacementChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TabControl tc = (TabControl)d;

            foreach (TabItem tabItem in tc.InternalChildren())
            {
                if (tabItem != null)
                {
                    tabItem.Dimension = null;
                    tabItem.CoerceValue(System.Windows.Controls.TabItem.TabStripPlacementProperty);
                }
            }
        }

        #endregion

        /*
         * Protected override methods
         * 
        */

        #region Overrides

        /// <summary>
        /// OnApplyTemplate override
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();

            // set up the event handler for the template parts
            _toggleButton = this.Template.FindName("PART_DropDown", this) as ToggleButton;
            if (_toggleButton != null)
            {
                // create a context menu for the togglebutton
                ContextMenu cm = new ContextMenu { PlacementTarget = _toggleButton, Placement = PlacementMode.Bottom };

                // create a binding between the togglebutton's IsChecked Property
                // and the Context Menu's IsOpen Property
                Binding b = new Binding
                {
                    Source = _toggleButton,
                    Mode = BindingMode.TwoWay,
                    Path = new PropertyPath(ToggleButton.IsCheckedProperty)
                };

                cm.SetBinding(ContextMenu.IsOpenProperty, b);

                _toggleButton.ContextMenu = cm;
                _toggleButton.Checked += DropdownButton_Checked;
            }

            ScrollViewer scrollViewer = this.Template.FindName("PART_ScrollViewer", this) as ScrollViewer;

            // set up event handlers for the RepeatButtons Click event
            RepeatButton repeatLeft = this.Template.FindName("PART_RepeatLeft", this) as RepeatButton;
            if (repeatLeft != null)
            {
                repeatLeft.Click += delegate
                {
                    if (scrollViewer != null)
                        scrollViewer.LineLeft();
                };
            }

            RepeatButton repeatRight = this.Template.FindName("PART_RepeatRight", this) as RepeatButton;
            if (repeatRight != null)
            {
                repeatRight.Click += delegate
                {
                    if (scrollViewer != null)
                        scrollViewer.LineRight();
                };
            }

            // set up the event handler for the 'New Tab' Button Click event
            _addNewButton = this.Template.FindName("PART_NewTabButton", this) as ButtonBase;
            if (_addNewButton != null)
                _addNewButton.Click += ((sender, routedEventArgs) => AddTabItem());
        }

        /// <summary>
        /// IsItemItsOwnContainerOverride
        /// </summary>
        /// <param name="item"></param>
        /// <returns></returns>
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return item is TabItem;
        }
        /// <summary>
        /// GetContainerForItemOverride
        /// </summary>
        /// <returns></returns>
        protected override DependencyObject GetContainerForItemOverride()
        {
            return new TabItem();
        }


        protected override void OnPreviewKeyDown(KeyEventArgs e)
        {
            var tabsCount = GetTabsCount();
            if (tabsCount == 0)
                return;

            TabItem ti = null;

            switch (e.Key)
            {
                case Key.Home:
                    ti = GetTabItem(0);
                    break;

                case Key.End:
                    ti = GetTabItem(tabsCount - 1);
                    break;

                case Key.Tab:
                    if (e.KeyboardDevice.Modifiers == ModifierKeys.Control)
                    {
                        var index = SelectedIndex;
                        var direction = e.KeyboardDevice.Modifiers == ModifierKeys.Shift ? -1 : 1;

                        while (true)
                        {
                            index += direction;
                            if (index < 0)
                                index = tabsCount - 1;
                            else if (index > tabsCount - 1)
                                index = 0;

                            FrameworkElement ui = GetTabItem(index);
                            if (ui != null)
                            {
                                if (ui.Visibility == Visibility.Visible && ui.IsEnabled)
                                {
                                    ti = GetTabItem(index);
                                    break;
                                }
                            }
                        }
                    }
                    break;
            }

            TabPanel panel = Helper.FindVirtualizingTabPanel(this);
            if (panel != null && ti != null)
            {
                panel.MakeVisible(ti, Rect.Empty);
                SelectedItem = ti;

                e.Handled = ti.Focus();
            }
            base.OnPreviewKeyDown(e);
        }

        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);

            if (e.Action == NotifyCollectionChangedAction.Add && SelectNewTabOnCreate)
            {
                TabItem tabItem = (TabItem)this.ItemContainerGenerator.ContainerFromItem(e.NewItems[e.NewItems.Count - 1]);
                SelectedItem = tabItem;

                TabPanel itemsHost = Helper.FindVirtualizingTabPanel(this);
                if (itemsHost != null)
                    itemsHost.MakeVisible(tabItem, Rect.Empty);

                tabItem.Focus();
            }
        }

        protected override void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue)
        {
            base.OnItemsSourceChanged(oldValue, newValue);

            IsUsingItemsSource = newValue != null;
            if (IsFixedSize)
                AllowAddNew = AllowDelete = false;

            SetAddNewButtonVisibility();
            SetTabItemsCloseButtonVisibility();
        }

        #endregion

        /// <summary>
        /// Handle the ToggleButton Checked event that displays a context menu of Header Headers
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void DropdownButton_Checked(object sender, RoutedEventArgs e)
        {
            if (_toggleButton == null) return;

            _toggleButton.ContextMenu.Items.Clear();
            _toggleButton.ContextMenu.Placement = TabStripPlacement == Dock.Bottom ? PlacementMode.Top : PlacementMode.Bottom;

            int index = 0;
            foreach (TabItem tabItem in this.InternalChildren())
            {
                if (tabItem != null)
                {
                    var header = Helper.CloneElement(tabItem.Header);
                    var icon = tabItem.Icon == null ? null : Helper.CloneElement(tabItem.Icon);

                    var mi = new MenuItem { Header = header, Icon = icon, Tag = index++.ToString() };
                    mi.Click += ContextMenuItem_Click;

                    _toggleButton.ContextMenu.Items.Add(mi);
                }
            }
        }

        /// <summary>
        /// Handle the MenuItem's Click event
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void ContextMenuItem_Click(object sender, RoutedEventArgs e)
        {
            MenuItem mi = sender as MenuItem;
            if (mi == null) return;

            int index;
            // get the index of the Header from the manuitems Tag property
            bool b = int.TryParse(mi.Tag.ToString(), out index);

            if (b)
            {
                TabItem tabItem = GetTabItem(index);
                if (tabItem != null)
                {
                    TabPanel itemsHost = Helper.FindVirtualizingTabPanel(this);
                    if (itemsHost != null)
                        itemsHost.MakeVisible(tabItem, Rect.Empty);

                    tabItem.Focus();
                }
            }
        }

        /// <summary>
        ///     Add a new Header
        /// </summary>
        public void AddTabItem()
        {
            if (IsFixedSize)
                throw new InvalidOperationException("ItemsSource is Fixed Size");

            int i = this.SelectedIndex;

            // give an opertunity to cancel the adding of the tabitem
            CancelEventArgs c = new CancelEventArgs();
            if (TabItemAdding != null)
                TabItemAdding(this, c);

            if (c.Cancel)
                return;

            TabItem tabItem;

            // Using ItemsSource property
            if (ItemsSource != null)
            {
                IList list = (IList)ItemsSource;
                NewTabItemEventArgs n = new NewTabItemEventArgs();
                if (NewTabItem == null)
                    throw new InvalidOperationException("You must implement the NewTabItem event to supply the item to be added to the tab control.");

                NewTabItem(this, n);
                if (n.Content == null)
                    return;

                if (i == -1 || i == list.Count - 1 || AddNewTabToEnd)
                    list.Add(n.Content);
                else
                    list.Insert(++i, n.Content);

                tabItem = (TabItem)this.ItemContainerGenerator.ContainerFromItem(n.Content);
            }
            else
            {
                // Using Items Property
                tabItem = new TabItem { Header = "New Tab" };

                if (i == -1 || i == this.Items.Count - 1 || AddNewTabToEnd)
                    this.Items.Add(tabItem);
                else
                    this.Items.Insert(++i, tabItem);
            }

            if (TabItemAdded != null)
                TabItemAdded(this, new TabItemEventArgs(tabItem));
        }

        /// <summary>
        /// Called by a child Header that wants to remove itself by clicking on the close button
        /// </summary>
        /// <param name="tabItem"></param>
        public void RemoveTabItem(TabItem tabItem)
        {
            if (IsFixedSize)
                throw new InvalidOperationException("ItemsSource is Fixed Size");

            // gives an opertunity to cancel the removal of the tabitem
            var c = new TabItemCancelEventArgs(tabItem);
            if (TabItemClosing != null)
                TabItemClosing(tabItem, c);

            if (c.Cancel)
                return;

            if (ItemsSource != null)
            {
                var list = ItemsSource as IList;
                object listItem = ItemContainerGenerator.ItemFromContainer(tabItem);
                if (listItem != null && list != null)
                    list.Remove(listItem);
            }
            else
                this.Items.Remove(tabItem);

            if (TabItemClosed != null)
                TabItemClosed(this, new TabItemEventArgs(tabItem));
        }

        private void SetAddNewButtonVisibility()
        {
            if (this.Template == null)
                return;

            ButtonBase button = this.Template.FindName("PART_NewTabButton", this) as ButtonBase;
            if (button == null) return;

            if (IsFixedSize)
                button.Visibility = Visibility.Collapsed;
            else
                button.Visibility = AllowAddNew
                                        ? Visibility.Visible
                                        : Visibility.Collapsed;
        }

        private void SetTabItemsCloseButtonVisibility()
        {
            bool isFixedSize = IsFixedSize;

            var tabsCount = GetTabsCount();
            for (int i = 0; i < tabsCount; i++)
            {
                TabItem ti = GetTabItem(i);
                if (ti != null)
                    ti.AllowDelete = !isFixedSize && this.AllowDelete;
            }
        }

        internal IEnumerable GetItems()
        {
            if (IsUsingItemsSource)
                return ItemsSource;
            return Items;
        }

        internal int GetTabsCount()
        {
            if (BindingOperations.IsDataBound(this, ItemsSourceProperty))
            {
                IList list = ItemsSource as IList;
                if (list != null)
                    return list.Count;

                // ItemsSource is only an IEnumerable
                int i = 0;
                IEnumerator enumerator = ItemsSource.GetEnumerator();
                while (enumerator.MoveNext())
                    i++;
                return i;
            }

            if (Items != null)
                return Items.Count;

            return 0;
        }

        internal TabItem GetTabItem(int index)
        {
            if (BindingOperations.IsDataBound(this, ItemsSourceProperty))
            {
                IList list = ItemsSource as IList;
                if (list != null)
                    return this.ItemContainerGenerator.ContainerFromItem(list[index]) as TabItem;

                // ItemsSource is at least an IEnumerable
                int i = 0;
                IEnumerator enumerator = ItemsSource.GetEnumerator();
                while (enumerator.MoveNext())
                {
                    if (i == index)
                        return this.ItemContainerGenerator.ContainerFromItem(enumerator.Current) as TabItem;
                    i++;
                }
                return null;
            }
            return Items[index] as TabItem;
        }

        private IEnumerable InternalChildren()
        {
            IEnumerator enumerator = GetItems().GetEnumerator();
            while (enumerator.MoveNext())
            {
                if (enumerator.Current is TabItem)
                    yield return enumerator.Current;
                else
                    yield return this.ItemContainerGenerator.ContainerFromItem(enumerator.Current) as TabItem;
            }
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions