TabControl.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / untmp / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / TabControl.cs / 1305600 / TabControl.cs

                            //---------------------------------------------------------------------------- 
//
// Copyright (C) Microsoft Corporation.  All rights reserved.
//
//--------------------------------------------------------------------------- 

using System.ComponentModel; 
using System.Collections; 
using System.Collections.Specialized;
using System.Diagnostics; 
using System.Globalization;
using System.Windows.Threading;
using System.Windows.Data;
using System.Windows.Input; 
using System.Windows;
using System.Windows.Automation.Peers; 
using System.Windows.Media; 
using System.Windows.Controls.Primitives;
using System.Windows.Markup; 
using MS.Utility;

using System;
 
namespace System.Windows.Controls
{ 
    ///  
    ///     TabControl allows a developer to arrange visual content in a compacted and organized form.
    /// The real-world analog of the control might be a tabbed notebook, 
    /// in which visual content is displayed in discreet pages which are accessed
    /// by selecting the appropriate tab.  Each tab/page is encapsulated by a TabItem,
    /// the generated item of TabControl.
    /// A TabItem has a Header property which corresponds to the content in the tab button 
    /// and a Content property which corresponds to the content in the tab page.
    /// This control is useful for minimizing screen space usage while allowing an application to expose a large amount of data. 
    /// The user navigates through TabItems by clicking on a tab button using the mouse or by using the keyboard. 
    /// 
    [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(TabItem))] 
    [TemplatePart(Name = "PART_SelectedContentHost", Type = typeof(ContentPresenter))]
    public class TabControl : Selector
    {
        #region Constructors 

        static TabControl() 
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TabControl), new FrameworkPropertyMetadata(typeof(TabControl)));
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(TabControl)); 
            IsTabStopProperty.OverrideMetadata(typeof(TabControl), new FrameworkPropertyMetadata(MS.Internal.KnownBoxes.BooleanBoxes.FalseBox));
            KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(TabControl), new FrameworkPropertyMetadata(KeyboardNavigationMode.Contained));

            IsEnabledProperty.OverrideMetadata(typeof(TabControl), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged))); 
        }
 
        ///  
        ///     Default TabControl constructor
        ///  
        /// 
        ///     Automatic determination of current Dispatcher. Use alternative constructor
        ///     that accepts a Dispatcher for best performance.
        ///  
        public TabControl() : base()
        { 
        } 

        #endregion 

        #region Properties

        ///  
        ///     The DependencyProperty for the TabStripPlacement property.
        ///     Flags:              None 
        ///     Default Value:      Dock.Top 
        /// 
        public static readonly DependencyProperty TabStripPlacementProperty = 
                    DependencyProperty.Register(
                            "TabStripPlacement",
                            typeof(Dock),
                            typeof(TabControl), 
                            new FrameworkPropertyMetadata(
                                    Dock.Top, 
                                    new PropertyChangedCallback(OnTabStripPlacementPropertyChanged)), 
                            new ValidateValueCallback(DockPanel.IsValidDock));
 
        // When TabControl TabStripPlacement is changing we need to invalidate its TabItem TabStripPlacement
        private static void OnTabStripPlacementPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TabControl tc = (TabControl)d; 
            ItemCollection tabItemCollection = tc.Items;
            for (int i = 0; i < tabItemCollection.Count; i++) 
            { 
                TabItem ti = tc.ItemContainerGenerator.ContainerFromIndex(i) as TabItem;
                if (ti != null) 
                    ti.CoerceValue(TabItem.TabStripPlacementProperty);
            }
        }
 
        /// 
        ///     TabStripPlacement specify how tab headers align relatively to content 
        ///  
        [Bindable(true), Category("Behavior")]
        public Dock TabStripPlacement 
        {
            get
            {
                return (Dock)GetValue(TabStripPlacementProperty); 
            }
            set 
            { 
                SetValue(TabStripPlacementProperty, value);
            } 
        }

        private static readonly DependencyPropertyKey SelectedContentPropertyKey = DependencyProperty.RegisterReadOnly("SelectedContent", typeof(object), typeof(TabControl), new FrameworkPropertyMetadata((object)null));
 
        /// 
        ///     The DependencyProperty for the SelectedContent property. 
        ///     Flags:              None 
        ///     Default Value:      null
        ///  
        public static readonly DependencyProperty SelectedContentProperty = SelectedContentPropertyKey.DependencyProperty;

        /// 
        ///     SelectedContent is the Content of current SelectedItem. 
        /// This property is updated whenever the selection is changed.
        /// It always keeps a reference to active TabItem.Content 
        /// Used for aliasing in default TabControl Style 
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public object SelectedContent
        {
            get
            { 
                return GetValue(SelectedContentProperty);
            } 
            internal set 
            {
                SetValue(SelectedContentPropertyKey, value); 
            }
        }

        private static readonly DependencyPropertyKey SelectedContentTemplatePropertyKey = DependencyProperty.RegisterReadOnly("SelectedContentTemplate", typeof(DataTemplate), typeof(TabControl), new FrameworkPropertyMetadata((DataTemplate)null)); 

        ///  
        ///     The DependencyProperty for the SelectedContentTemplate property. 
        ///     Flags:              None
        ///     Default Value:      null 
        /// 
        public static readonly DependencyProperty SelectedContentTemplateProperty = SelectedContentTemplatePropertyKey.DependencyProperty;

        ///  
        ///     SelectedContentTemplate is the ContentTemplate of current SelectedItem.
        /// This property is updated whenever the selection is changed. 
        /// It always keeps a reference to active TabItem.ContentTemplate 
        /// It is used for aliasing in default TabControl Style
        ///  
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public DataTemplate SelectedContentTemplate
        { 
            get
            { 
                return (DataTemplate)GetValue(SelectedContentTemplateProperty); 
            }
            internal set 
            {
                SetValue(SelectedContentTemplatePropertyKey, value);
            }
        } 

        private static readonly DependencyPropertyKey SelectedContentTemplateSelectorPropertyKey = DependencyProperty.RegisterReadOnly("SelectedContentTemplateSelector", typeof(DataTemplateSelector), typeof(TabControl), new FrameworkPropertyMetadata((DataTemplateSelector)null)); 
 
        /// 
        ///     The DependencyProperty for the SelectedContentTemplateSelector property. 
        ///     Flags:              None
        ///     Default Value:      null
        /// 
        public static readonly DependencyProperty SelectedContentTemplateSelectorProperty = SelectedContentTemplateSelectorPropertyKey.DependencyProperty; 

        ///  
        ///     SelectedContentTemplateSelector allows the app writer to provide custom style selection logic. 
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public DataTemplateSelector SelectedContentTemplateSelector
        {
            get
            { 
                return (DataTemplateSelector)GetValue(SelectedContentTemplateSelectorProperty);
            } 
            internal set 
            {
                SetValue(SelectedContentTemplateSelectorPropertyKey, value); 
            }
        }

        private static readonly DependencyPropertyKey SelectedContentStringFormatPropertyKey = 
                DependencyProperty.RegisterReadOnly("SelectedContentStringFormat",
                        typeof(String), 
                        typeof(TabControl), 
                        new FrameworkPropertyMetadata((String)null));
 
        /// 
        ///     The DependencyProperty for the SelectedContentStringFormat property.
        ///     Flags:              None
        ///     Default Value:      null 
        /// 
        public static readonly DependencyProperty SelectedContentStringFormatProperty = 
                SelectedContentStringFormatPropertyKey.DependencyProperty; 

 
        /// 
        ///     ContentStringFormat is the format used to display the content of
        ///     the control as a string.  This arises only when no template is
        ///     available. 
        /// 
        public String SelectedContentStringFormat 
        { 
            get { return (String) GetValue(SelectedContentStringFormatProperty); }
            internal set { SetValue(SelectedContentStringFormatPropertyKey, value); } 
        }


        ///  
        ///     The DependencyProperty for the ContentTemplate property.
        ///     Flags:              None 
        ///     Default Value:      null 
        /// 
        public static readonly DependencyProperty ContentTemplateProperty = DependencyProperty.Register("ContentTemplate", typeof(DataTemplate), typeof(TabControl), new FrameworkPropertyMetadata((DataTemplate)null)); 

        /// 
        /// ContentTemplate is the ContentTemplate to apply to TabItems
        /// that do not have the ContentTemplate or ContentTemplateSelector properties 
        /// defined
        ///  
        ///  
        public DataTemplate ContentTemplate
        { 
            get
            {
                return (DataTemplate)GetValue(ContentTemplateProperty);
            } 
            set
            { 
                SetValue(ContentTemplateProperty, value); 
            }
        } 

        /// 
        ///     The DependencyProperty for the ContentTemplateSelector property.
        ///     Flags:              None 
        ///     Default Value:      null
        ///  
        public static readonly DependencyProperty ContentTemplateSelectorProperty = DependencyProperty.Register("ContentTemplateSelector", typeof(DataTemplateSelector), typeof(TabControl), new FrameworkPropertyMetadata((DataTemplateSelector)null)); 

        ///  
        ///     ContentTemplateSelector allows the app writer to provide custom style selection logic.
        /// 
        public DataTemplateSelector ContentTemplateSelector
        { 
            get
            { 
                return (DataTemplateSelector)GetValue(ContentTemplateSelectorProperty); 
            }
            set 
            {
                SetValue(ContentTemplateSelectorProperty, value);
            }
        } 

        ///  
        ///     The DependencyProperty for the ContentStringFormat property. 
        ///     Flags:              None
        ///     Default Value:      null 
        /// 
        public static readonly DependencyProperty ContentStringFormatProperty =
                DependencyProperty.Register(
                        "ContentStringFormat", 
                        typeof(String),
                        typeof(TabControl), 
                        new FrameworkPropertyMetadata((String) null)); 

 
        /// 
        ///     ContentStringFormat is the format used to display the content of
        ///     the control as a string.  This arises only when no template is
        ///     available. 
        /// 
        public String ContentStringFormat 
        { 
            get { return (String) GetValue(ContentStringFormatProperty); }
            set { SetValue(ContentStringFormatProperty, value); } 
        }

        #endregion
 
        #region Overrided Methods
 
        internal override void ChangeVisualState(bool useTransitions) 
        {
            if (!IsEnabled) 
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateDisabled, VisualStates.StateNormal);
            }
            else 
            {
                VisualStateManager.GoToState(this, VisualStates.StateNormal, useTransitions); 
            } 

            base.ChangeVisualState(useTransitions); 
        }

        /// 
        /// Creates AutomationPeer () 
        /// 
        protected override AutomationPeer OnCreateAutomationPeer() 
        { 
            return new TabControlAutomationPeer(this);
        } 

        /// 
        ///     This virtual method in called when IsInitialized is set to true and it raises an Initialized event
        ///  
        protected override void OnInitialized(EventArgs e)
        { 
            base.OnInitialized(e); 
            CanSelectMultiple = false;
            ItemContainerGenerator.StatusChanged += new EventHandler(OnGeneratorStatusChanged); 
        }
        /// 
        /// Called when the Template's tree has been generated. When Template gets expanded we ensure that SelectedContent is in [....]
        ///  
        public override void OnApplyTemplate()
        { 
            base.OnApplyTemplate(); 
            UpdateSelectedContent();
        } 

        /// 
        /// A virtual function that is called when the selection is changed. Default behavior
        /// is to raise a SelectionChangedEvent 
        /// 
        /// The inputs for this event. Can be raised (default behavior) or processed 
        ///   in some other way. 
        protected override void OnSelectionChanged(SelectionChangedEventArgs e)
        { 
            base.OnSelectionChanged(e);
            if (IsKeyboardFocusWithin)
            {
                // If keyboard focus is within the control, make sure it is going to the correct place 
                TabItem item = GetSelectedTabItem();
                if (item != null) 
                { 
                    item.SetFocus();
                } 
            }
            UpdateSelectedContent();

            if (    AutomationPeer.ListenerExists(AutomationEvents.SelectionPatternOnInvalidated) 
                ||  AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementSelected)
                ||  AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementAddedToSelection) 
                ||  AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection)   ) 
            {
                TabControlAutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(this) as TabControlAutomationPeer; 
                if (peer != null)
                    peer.RaiseSelectionEvents(e);
            }
        } 

        ///  
        /// Updates the current selection when Items has changed 
        /// 
        /// Information about what has changed 
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            base.OnItemsChanged(e);
            if (e.Action == NotifyCollectionChangedAction.Remove && SelectedIndex == -1) 
            {
                // If we remove the selected item we should select the previous item 
                int startIndex = e.OldStartingIndex + 1; 
                if (startIndex > Items.Count)
                    startIndex = 0; 
                TabItem nextTabItem = FindNextTabItem(startIndex, -1);
                if (nextTabItem != null)
                    nextTabItem.SetCurrentValueInternal(TabItem.IsSelectedProperty, MS.Internal.KnownBoxes.BooleanBoxes.TrueBox);
            } 
        }
 
        ///  
        /// This is the method that responds to the KeyDown event.
        ///  
        /// 
        protected override void OnKeyDown(KeyEventArgs e)
        {
            TabItem nextTabItem = null; 

            // Handle [Ctrl][Shift]Tab, Home and End cases 
            // We have special handling here because if focus is inside the TabItem content we cannot 
            // cycle through TabItem because the content is not part of the TabItem visual tree
 
            int direction = 0;
            int startIndex = -1;
            switch (e.Key)
            { 
                case Key.Tab:
                    if ((e.KeyboardDevice.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) 
                    { 
                        startIndex = ItemContainerGenerator.IndexFromContainer(ItemContainerGenerator.ContainerFromItem(SelectedItem));
                        if ((e.KeyboardDevice.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift) 
                            direction = -1;
                        else
                            direction = 1;
                    } 
                    break;
                case Key.Home: 
                    direction = 1; 
                    startIndex = -1;
                    break; 
                case Key.End:
                    direction = -1;
                    startIndex = Items.Count;
                    break; 
            }
 
            nextTabItem = FindNextTabItem(startIndex, direction); 

            if (nextTabItem != null && nextTabItem != SelectedItem) 
            {
                e.Handled = nextTabItem.SetFocus();
            }
 
            if (!e.Handled)
                base.OnKeyDown(e); 
        } 

        private TabItem FindNextTabItem(int startIndex, int direction) 
        {
            TabItem nextTabItem = null;
            if (direction != 0)
            { 
                int index = startIndex;
                for (int i = 0; i < Items.Count; i++) 
                { 
                    index += direction;
                    if (index >= Items.Count) 
                        index = 0;
                    else if (index < 0)
                        index = Items.Count - 1;
 
                    TabItem tabItem = ItemContainerGenerator.ContainerFromIndex(index) as TabItem;
                    if (tabItem != null && tabItem.IsEnabled && tabItem.Visibility == Visibility.Visible) 
                    { 
                        nextTabItem = tabItem;
                        break; 
                    }
                }
            }
            return nextTabItem; 
        }
 
        ///  
        /// Return true if the item is (or is eligible to be) its own ItemUI
        ///  
        protected override bool IsItemItsOwnContainerOverride(object item)
        {
            return (item is TabItem);
        } 

        ///  Create or identify the element used to display the given item.  
        protected override DependencyObject GetContainerForItemOverride() 
        {
            return new TabItem(); 
        }

        #endregion
 
        #region private helpers
 
        internal ContentPresenter SelectedContentPresenter 
        {
            get 
            {
                return GetTemplateChild(SelectedContentHostTemplateName) as ContentPresenter;
            }
        } 

        private void OnGeneratorStatusChanged(object sender, EventArgs e) 
        { 
            if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
            { 
                if (HasItems && _selectedItems.Count == 0)
                {
                    SetCurrentValueInternal(SelectedIndexProperty, 0);
                } 

                UpdateSelectedContent(); 
            } 
        }
 
        private TabItem GetSelectedTabItem()
        {
            object selectedItem = SelectedItem;
            if (selectedItem != null) 
            {
                // Check if the selected item is a TabItem 
                TabItem tabItem = selectedItem as TabItem; 
                if (tabItem == null)
                { 
                    // It is a data item, get its TabItem container
                    tabItem = ItemContainerGenerator.ContainerFromIndex(SelectedIndex) as TabItem;

                    // Due to event leapfrogging, we may have the wrong container. 
                    // If so, re-fetch the right container using a more expensive method.
                    // (BTW, the previous line will cause a debug assert in this case)  [Dev10 452711] 
                    if (tabItem != null && 
                        !Object.Equals(selectedItem, ItemContainerGenerator.ItemFromContainer(tabItem)))
                    { 
                        tabItem = ItemContainerGenerator.ContainerFromItem(selectedItem) as TabItem;
                    }
                }
 
                return tabItem;
            } 
 
            return null;
        } 

        // When selection is changed we need to copy the active TabItem content in SelectedContent property
        // SelectedContent is aliased in the TabControl style
        private void UpdateSelectedContent() 
        {
            if (SelectedIndex < 0) 
            { 
                SelectedContent = null;
                SelectedContentTemplate = null; 
                SelectedContentTemplateSelector = null;
                SelectedContentStringFormat = null;
                return;
            } 

            TabItem tabItem = GetSelectedTabItem(); 
            if (tabItem != null) 
            {
                FrameworkElement visualParent = VisualTreeHelper.GetParent(tabItem) as FrameworkElement; 

                if (visualParent != null)
                {
                    KeyboardNavigation.SetTabOnceActiveElement(visualParent, tabItem); 
                    KeyboardNavigation.SetTabOnceActiveElement(this, visualParent);
                } 
 
                SelectedContent = tabItem.Content;
                ContentPresenter scp = SelectedContentPresenter; 
                if (scp != null)
                {
                    scp.HorizontalAlignment = tabItem.HorizontalContentAlignment;
                    scp.VerticalAlignment = tabItem.VerticalContentAlignment; 
                }
 
                // Use tabItem's template or selector if specified, otherwise use TabControl's 
                if (tabItem.ContentTemplate != null || tabItem.ContentTemplateSelector != null || tabItem.ContentStringFormat != null)
                { 
                    SelectedContentTemplate = tabItem.ContentTemplate;
                    SelectedContentTemplateSelector = tabItem.ContentTemplateSelector;
                    SelectedContentStringFormat = tabItem.ContentStringFormat;
                } 
                else
                { 
                    SelectedContentTemplate = ContentTemplate; 
                    SelectedContentTemplateSelector = ContentTemplateSelector;
                    SelectedContentStringFormat = ContentStringFormat; 
                }
             }
        }
 
        #endregion private helpers
 
        #region private data 

        // Part name used in the style. The class TemplatePartAttribute should use the same name 
        private const string SelectedContentHostTemplateName = "PART_SelectedContentHost";

        #endregion
 
        #region DTypeThemeStyleKey
 
        // Returns the DependencyObjectType for the registered ThemeStyleKey's default 
        // value. Controls will override this method to return approriate types.
        internal override DependencyObjectType DTypeThemeStyleKey 
        {
            get { return _dType; }
        }
 
        private static DependencyObjectType _dType;
 
        #endregion DTypeThemeStyleKey 
    }
} 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
// Copyright (c) Microsoft Corporation. All rights reserved.
                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK