ItemsControl.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 / ItemsControl.cs / 1458001 / ItemsControl.cs

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

using System; 
using System.Collections; 
using System.Collections.Generic;
using System.Collections.ObjectModel; 
using System.Collections.Specialized;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Threading; 
using System.Windows.Controls.Primitives;
using System.Windows.Data; 
using System.Windows; 
using System.Windows.Media;
using System.Windows.Markup; 
using System.Windows.Input;

using MS.Utility;
using MS.Internal; 
using MS.Internal.Controls;
using MS.Internal.Data; 
using MS.Internal.Hashing.PresentationFramework;    // HashHelper 
using MS.Internal.KnownBoxes;
using MS.Internal.PresentationFramework; 
using MS.Internal.Utility;

namespace System.Windows.Controls
{ 
    /// 
    ///     The base class for all controls that have multiple children. 
    ///  
    /// 
    ///     ItemsControl adds Items, ItemTemplate, and Part features to a Control. 
    /// 
    //
    [DefaultEvent("OnItemsChanged"), DefaultProperty("Items")]
    [ContentProperty("Items")] 
    [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(FrameworkElement))]
    [Localizability(LocalizationCategory.None, Readability = Readability.Unreadable)] // cannot be read & localized as string 
    public class ItemsControl : Control, IAddChild, IGeneratorHost 
    {
        #region Constructors 

        /// 
        ///     Default ItemsControl constructor
        ///  
        /// 
        ///     Automatic determination of current Dispatcher. Use alternative constructor 
        ///     that accepts a Dispatcher for best performance. 
        /// 
        public ItemsControl() : base() 
        {
        }

        static ItemsControl() 
        {
            // 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ItemsControl), new FrameworkPropertyMetadata(typeof(ItemsControl))); 
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(ItemsControl));
            EventManager.RegisterClassHandler(typeof(ItemsControl), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnGotFocus)); 
        }

        private void CreateItemCollectionAndGenerator()
        { 
            _items = new ItemCollection(this);
 
            // the generator must attach its collection change handler before 
            // the control itself, so that the generator is up-to-date by the
            // time the control tries to use it (bug 892806 et al.) 
            _itemContainerGenerator = new ItemContainerGenerator(this);

            _itemContainerGenerator.ChangeAlternationCount();
 
            ((INotifyCollectionChanged)_items).CollectionChanged += new NotifyCollectionChangedEventHandler(OnItemCollectionChanged);
 
            if (IsInitPending) 
            {
                _items.BeginInit(); 
            }
            else if (IsInitialized)
            {
                _items.BeginInit(); 
                _items.EndInit();
            } 
 
            ((INotifyCollectionChanged)_groupStyle).CollectionChanged += new NotifyCollectionChangedEventHandler(OnGroupStyleChanged);
        } 

        #endregion

        #region Properties 

        ///  
        ///     Items is the collection of data that is used to generate the content 
        ///     of this control.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
        [Bindable(true), CustomCategory("Content")]
        public ItemCollection Items
        { 
            get
            { 
                if (_items == null) 
                {
                    CreateItemCollectionAndGenerator(); 
                }

                return _items;
            } 
        }
 
        ///  
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized. 
        /// 
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeItems()
        { 
            return HasItems;
        } 
 
        /// 
        ///     The DependencyProperty for the ItemsSource property. 
        ///     Flags:              None
        ///     Default Value:      null
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ItemsSourceProperty
            = DependencyProperty.Register("ItemsSource", typeof(IEnumerable), typeof(ItemsControl), 
                                          new FrameworkPropertyMetadata((IEnumerable)null, 
                                                                        new PropertyChangedCallback(OnItemsSourceChanged)));
 
        private static void OnItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ItemsControl ic = (ItemsControl) d;
            IEnumerable oldValue = (IEnumerable)e.OldValue; 
            IEnumerable newValue = (IEnumerable)e.NewValue;
 
            ItemValueStorageField.ClearValue(d); 

            // distinguish between an explicit null value and one arising from 
            // a Binding.  The former means to return to normal mode,
            // the latter means to use ItemsSource mode, but with a
            // null collection.
            if (e.NewValue == null && !BindingOperations.IsDataBound(d, ItemsSourceProperty)) 
            {
                ic.Items.ClearItemsSource(); 
            } 
            else
            { 
                ic.Items.SetItemsSource(newValue);
            }
            ic.OnItemsSourceChanged(oldValue, newValue);
        } 

        ///  
        /// Called when the value of ItemsSource changes. 
        /// 
        protected virtual void OnItemsSourceChanged(IEnumerable oldValue, IEnumerable newValue) 
        {
        }

        ///  
        ///     ItemsSource specifies a collection used to generate the content of
        /// this control.  This provides a simple way to use exactly one collection 
        /// as the source of content for this control. 
        /// 
        ///  
        ///     Any existing contents of the Items collection is replaced when this
        /// property is set. The Items collection will be made ReadOnly and FixedSize.
        ///     When ItemsSource is in use, setting this property to null will remove
        /// the collection and restore use to Items (which will be an empty ItemCollection). 
        ///     When ItemsSource is not in use, the value of this property is null, and
        /// setting it to null has no effect. 
        ///  
        [Bindable(true), CustomCategory("Content")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public IEnumerable ItemsSource
        {
            get { return Items.ItemsSource; }
            set 
            {
                if (value == null) 
                { 
                    ClearValue(ItemsSourceProperty);
                } 
                else
                {
                    SetValue(ItemsSourceProperty, value);
                } 
            }
        } 
 
        /// 
        /// The ItemContainerGenerator associated with this control 
        /// 
        [Bindable(false), Browsable(false), EditorBrowsable(EditorBrowsableState.Advanced)]
        public ItemContainerGenerator ItemContainerGenerator
        { 
            get
            { 
                if (_itemContainerGenerator == null) 
                {
                    CreateItemCollectionAndGenerator(); 
                }

                return _itemContainerGenerator;
            } 
        }
 
        ///  
        ///     Returns enumerator to logical children
        ///  
        protected internal override IEnumerator LogicalChildren
        {
            get
            { 
                if (!HasItems)
                { 
                    return EmptyEnumerator.Instance; 
                }
 
                // Items in direct-mode of ItemCollection are the only model children.
                // note: the enumerator walks the ItemCollection.InnerList as-is,
                // no flattening of any content on model children level!
                return this.Items.LogicalChildren; 
            }
        } 
 
        private void OnItemCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        { 
            SetValue(HasItemsPropertyKey, (_items != null) && !_items.IsEmpty);

            // If the focused item is removed, drop our reference to it.
            if ((e.Action == NotifyCollectionChangedAction.Remove && _focusedItem != null && _focusedItem.Equals(e.OldItems[0])) 
                || (e.Action == NotifyCollectionChangedAction.Reset))
            { 
                _focusedItem = null; 
            }
 
            OnItemsChanged(e);
        }

        ///  
        ///     This method is invoked when the Items property changes.
        ///  
        protected virtual void OnItemsChanged(NotifyCollectionChangedEventArgs e) 
        {
        } 

        /// 
        ///     The key needed set a read-only property.
        ///  
        internal static readonly DependencyPropertyKey HasItemsPropertyKey =
                DependencyProperty.RegisterReadOnly( 
                        "HasItems", 
                        typeof(bool),
                        typeof(ItemsControl), 
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox, OnVisualStatePropertyChanged));

        /// 
        ///     The DependencyProperty for the HasItems property. 
        ///     Flags:              None
        ///     Other:              Read-Only 
        ///     Default Value:      false 
        /// 
        public static readonly DependencyProperty HasItemsProperty = 
                HasItemsPropertyKey.DependencyProperty;

        /// 
        ///     True if Items.Count > 0, false otherwise. 
        /// 
        [Bindable(false), Browsable(false)] 
        public bool HasItems 
        {
            get { return (bool) GetValue(HasItemsProperty); } 
        }

        /// 
        ///     The DependencyProperty for the DisplayMemberPath property. 
        ///     Flags:              none
        ///     Default Value:      string.Empty 
        ///  
        public static readonly DependencyProperty DisplayMemberPathProperty =
                DependencyProperty.Register( 
                        "DisplayMemberPath",
                        typeof(string),
                        typeof(ItemsControl),
                        new FrameworkPropertyMetadata( 
                                string.Empty,
                                new PropertyChangedCallback(OnDisplayMemberPathChanged))); 
 
        /// 
        ///     DisplayMemberPath is a simple way to define a default template 
        ///     that describes how to convert Items into UI elements by using
        ///     the specified path.
        /// 
        [Bindable(true), CustomCategory("Content")] 
        public string DisplayMemberPath
        { 
            get { return (string) GetValue(DisplayMemberPathProperty); } 
            set { SetValue(DisplayMemberPathProperty, value); }
        } 

        /// 
        ///     Called when DisplayMemberPathProperty is invalidated on "d."
        ///  
        private static void OnDisplayMemberPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ItemsControl ctrl = (ItemsControl) d; 

            ctrl.OnDisplayMemberPathChanged((string)e.OldValue, (string)e.NewValue); 
            ctrl.UpdateDisplayMemberTemplateSelector();
        }

        // DisplayMemberPath and ItemStringFormat use the ItemTemplateSelector property 
        // to achieve the desired result.  When either of these properties change,
        // update the ItemTemplateSelector property here. 
        private void UpdateDisplayMemberTemplateSelector() 
        {
            string displayMemberPath = DisplayMemberPath; 
            string itemStringFormat = ItemStringFormat;

            if (!String.IsNullOrEmpty(displayMemberPath) || !String.IsNullOrEmpty(itemStringFormat))
            { 
                // One or both of DisplayMemberPath and ItemStringFormat are desired.
                // Set ItemTemplateSelector to an appropriate object, provided that 
                // this doesn't conflict with the user's own setting. 
                DataTemplateSelector itemTemplateSelector = ItemTemplateSelector;
                if (itemTemplateSelector != null && !(itemTemplateSelector is DisplayMemberTemplateSelector)) 
                {
                    // if ITS was actually set to something besides a DisplayMember selector,
                    // it's an error to overwrite it with a DisplayMember selector
                    // unless ITS came from a style and DMP is local 
                    if (ReadLocalValue(ItemTemplateSelectorProperty) != DependencyProperty.UnsetValue ||
                        ReadLocalValue(DisplayMemberPathProperty) == DependencyProperty.UnsetValue) 
                    { 
                        throw new InvalidOperationException(SR.Get(SRID.DisplayMemberPathAndItemTemplateSelectorDefined));
                    } 
                }

                // now set the ItemTemplateSelector to use the new DisplayMemberPath and ItemStringFormat
                ItemTemplateSelector = new DisplayMemberTemplateSelector(DisplayMemberPath, ItemStringFormat); 
            }
            else 
            { 
                // Neither property is desired.  Clear the ItemTemplateSelector if
                // we had set it earlier. 
                if (ItemTemplateSelector is DisplayMemberTemplateSelector)
                {
                    ClearValue(ItemTemplateSelectorProperty);
                } 
            }
        } 
 
        /// 
        ///     This method is invoked when the DisplayMemberPath property changes. 
        /// 
        /// The old value of the DisplayMemberPath property.
        /// The new value of the DisplayMemberPath property.
        protected virtual void OnDisplayMemberPathChanged(string oldDisplayMemberPath, string newDisplayMemberPath) 
        {
        } 
 
        /// 
        ///     The DependencyProperty for the ItemTemplate property. 
        ///     Flags:              none
        ///     Default Value:      null
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ItemTemplateProperty =
                DependencyProperty.Register( 
                        "ItemTemplate", 
                        typeof(DataTemplate),
                        typeof(ItemsControl), 
                        new FrameworkPropertyMetadata(
                                (DataTemplate) null,
                                new PropertyChangedCallback(OnItemTemplateChanged)));
 
        /// 
        ///     ItemTemplate is the template used to display each item. 
        ///  
        [Bindable(true), CustomCategory("Content")]
        public DataTemplate ItemTemplate 
        {
            get { return (DataTemplate) GetValue(ItemTemplateProperty); }
            set { SetValue(ItemTemplateProperty, value); }
        } 

        ///  
        ///     Called when ItemTemplateProperty is invalidated on "d." 
        /// 
        /// The object on which the property was invalidated. 
        /// EventArgs that contains the old and new values for this property
        private static void OnItemTemplateChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ItemsControl) d).OnItemTemplateChanged((DataTemplate) e.OldValue, (DataTemplate) e.NewValue); 
        }
 
        ///  
        ///     This method is invoked when the ItemTemplate property changes.
        ///  
        /// The old value of the ItemTemplate property.
        /// The new value of the ItemTemplate property.
        protected virtual void OnItemTemplateChanged(DataTemplate oldItemTemplate, DataTemplate newItemTemplate)
        { 
            CheckTemplateSource();
 
            if (_itemContainerGenerator != null) 
            {
                _itemContainerGenerator.Refresh(); 
            }
        }

 
        /// 
        ///     The DependencyProperty for the ItemTemplateSelector property. 
        ///     Flags:              none 
        ///     Default Value:      null
        ///  
        [CommonDependencyProperty]
        public static readonly DependencyProperty ItemTemplateSelectorProperty =
                DependencyProperty.Register(
                        "ItemTemplateSelector", 
                        typeof(DataTemplateSelector),
                        typeof(ItemsControl), 
                        new FrameworkPropertyMetadata( 
                                (DataTemplateSelector) null,
                                new PropertyChangedCallback(OnItemTemplateSelectorChanged))); 

        /// 
        ///     ItemTemplateSelector allows the application writer to provide custom logic
        ///     for choosing the template used to display each item. 
        /// 
        ///  
        ///     This property is ignored if  is set. 
        /// 
        [Bindable(true), CustomCategory("Content")] 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
        public DataTemplateSelector ItemTemplateSelector
        {
            get { return (DataTemplateSelector) GetValue(ItemTemplateSelectorProperty); } 
            set { SetValue(ItemTemplateSelectorProperty, value); }
        } 
 
        /// 
        ///     Called when ItemTemplateSelectorProperty is invalidated on "d." 
        /// 
        /// The object on which the property was invalidated.
        /// EventArgs that contains the old and new values for this property
        private static void OnItemTemplateSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            ((ItemsControl)d).OnItemTemplateSelectorChanged((DataTemplateSelector) e.OldValue, (DataTemplateSelector) e.NewValue); 
        } 

        ///  
        ///     This method is invoked when the ItemTemplateSelector property changes.
        /// 
        /// The old value of the ItemTemplateSelector property.
        /// The new value of the ItemTemplateSelector property. 
        protected virtual void OnItemTemplateSelectorChanged(DataTemplateSelector oldItemTemplateSelector, DataTemplateSelector newItemTemplateSelector)
        { 
            CheckTemplateSource(); 

            if ((_itemContainerGenerator != null) && (ItemTemplate == null)) 
            {
                _itemContainerGenerator.Refresh();
            }
        } 

        ///  
        ///     The DependencyProperty for the ItemStringFormat property. 
        ///     Flags:              None
        ///     Default Value:      null 
        /// 
        [CommonDependencyProperty]
        public static readonly DependencyProperty ItemStringFormatProperty =
                DependencyProperty.Register( 
                        "ItemStringFormat",
                        typeof(String), 
                        typeof(ItemsControl), 
                        new FrameworkPropertyMetadata(
                                (String) null, 
                              new PropertyChangedCallback(OnItemStringFormatChanged)));


        ///  
        ///     ItemStringFormat is the format used to display an item (or a
        ///     property of an item, as declared by DisplayMemberPath) as a string. 
        ///     This arises only when no template is available. 
        /// 
        [Bindable(true), CustomCategory("Content")] 
        public String ItemStringFormat
        {
            get { return (String) GetValue(ItemStringFormatProperty); }
            set { SetValue(ItemStringFormatProperty, value); } 
        }
 
        ///  
        ///     Called when ItemStringFormatProperty is invalidated on "d."
        ///  
        private static void OnItemStringFormatChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ItemsControl ctrl = (ItemsControl)d;
 
            ctrl.OnItemStringFormatChanged((String) e.OldValue, (String) e.NewValue);
            ctrl.UpdateDisplayMemberTemplateSelector(); 
        } 

        ///  
        ///     This method is invoked when the ItemStringFormat property changes.
        /// 
        /// The old value of the ItemStringFormat property.
        /// The new value of the ItemStringFormat property. 
        protected virtual void OnItemStringFormatChanged(String oldItemStringFormat, String newItemStringFormat)
        { 
        } 

 
        /// 
        ///     The DependencyProperty for the ItemBindingGroup property.
        ///     Flags:              None
        ///     Default Value:      null 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ItemBindingGroupProperty = 
                DependencyProperty.Register(
                        "ItemBindingGroup", 
                        typeof(BindingGroup),
                        typeof(ItemsControl),
                        new FrameworkPropertyMetadata(
                                (BindingGroup) null, 
                              new PropertyChangedCallback(OnItemBindingGroupChanged)));
 
 
        /// 
        ///     ItemBindingGroup declares a BindingGroup to be used as a "master" 
        ///     for the generated containers.  Each container's BindingGroup is set
        ///     to a copy of the master, sharing the same set of validation rules,
        ///     but managing its own collection of bindings.
        ///  
        [Bindable(true), CustomCategory("Content")]
        public BindingGroup ItemBindingGroup 
        { 
            get { return (BindingGroup) GetValue(ItemBindingGroupProperty); }
            set { SetValue(ItemBindingGroupProperty, value); } 
        }

        /// 
        ///     Called when ItemBindingGroupProperty is invalidated on "d." 
        /// 
        private static void OnItemBindingGroupChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
            ItemsControl ctrl = (ItemsControl)d;
 
            ctrl.OnItemBindingGroupChanged((BindingGroup) e.OldValue, (BindingGroup) e.NewValue);
        }

        ///  
        ///     This method is invoked when the ItemBindingGroup property changes.
        ///  
        /// The old value of the ItemBindingGroup property. 
        /// The new value of the ItemBindingGroup property.
        protected virtual void OnItemBindingGroupChanged(BindingGroup oldItemBindingGroup, BindingGroup newItemBindingGroup) 
        {
        }

 
        /// 
        /// Throw if more than one of DisplayMemberPath, xxxTemplate and xxxTemplateSelector 
        /// properties are set on the given element. 
        /// 
        private void CheckTemplateSource() 
        {
            if (string.IsNullOrEmpty(DisplayMemberPath))
            {
                Helper.CheckTemplateAndTemplateSelector("Item", ItemTemplateProperty, ItemTemplateSelectorProperty, this); 
            }
            else 
            { 
                if (!(this.ItemTemplateSelector is DisplayMemberTemplateSelector))
                { 
                    throw new InvalidOperationException(SR.Get(SRID.ItemTemplateSelectorBreaksDisplayMemberPath));
                }
                if (Helper.IsTemplateDefined(ItemTemplateProperty, this))
                { 
                    throw new InvalidOperationException(SR.Get(SRID.DisplayMemberPathAndItemTemplateDefined));
                } 
            } 
        }
 
        /// 
        ///     The DependencyProperty for the ItemContainerStyle property.
        ///     Flags:              none
        ///     Default Value:      null 
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ItemContainerStyleProperty = 
                DependencyProperty.Register(
                        "ItemContainerStyle", 
                        typeof(Style),
                        typeof(ItemsControl),
                        new FrameworkPropertyMetadata(
                                (Style) null, 
                                new PropertyChangedCallback(OnItemContainerStyleChanged)));
 
        ///  
        ///     ItemContainerStyle is the style that is applied to the container element generated
        ///     for each item. 
        /// 
        [Bindable(true), Category("Content")]
        public Style ItemContainerStyle
        { 
            get { return (Style) GetValue(ItemContainerStyleProperty); }
            set { SetValue(ItemContainerStyleProperty, value); } 
        } 

        ///  
        ///     Called when ItemContainerStyleProperty is invalidated on "d."
        /// 
        /// The object on which the property was invalidated.
        /// EventArgs that contains the old and new values for this property 
        private static void OnItemContainerStyleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ((ItemsControl) d).OnItemContainerStyleChanged((Style) e.OldValue, (Style) e.NewValue); 
        }
 
        /// 
        ///     This method is invoked when the ItemContainerStyle property changes.
        /// 
        /// The old value of the ItemContainerStyle property. 
        /// The new value of the ItemContainerStyle property.
        protected virtual void OnItemContainerStyleChanged(Style oldItemContainerStyle, Style newItemContainerStyle) 
        { 
            Helper.CheckStyleAndStyleSelector("ItemContainer", ItemContainerStyleProperty, ItemContainerStyleSelectorProperty, this);
 
            if (_itemContainerGenerator != null)
            {
                _itemContainerGenerator.Refresh();
            } 
        }
 
 
        /// 
        ///     The DependencyProperty for the ItemContainerStyleSelector property. 
        ///     Flags:              none
        ///     Default Value:      null
        /// 
        [CommonDependencyProperty] 
        public static readonly DependencyProperty ItemContainerStyleSelectorProperty =
                DependencyProperty.Register( 
                        "ItemContainerStyleSelector", 
                        typeof(StyleSelector),
                        typeof(ItemsControl), 
                        new FrameworkPropertyMetadata(
                                (StyleSelector) null,
                                new PropertyChangedCallback(OnItemContainerStyleSelectorChanged)));
 
        /// 
        ///     ItemContainerStyleSelector allows the application writer to provide custom logic 
        ///     to choose the style to apply to each generated container element. 
        /// 
        ///  
        ///     This property is ignored if  is set.
        /// 
        [Bindable(true), Category("Content")]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public StyleSelector ItemContainerStyleSelector
        { 
            get { return (StyleSelector) GetValue(ItemContainerStyleSelectorProperty); } 
            set { SetValue(ItemContainerStyleSelectorProperty, value); }
        } 

        /// 
        ///     Called when ItemContainerStyleSelectorProperty is invalidated on "d."
        ///  
        /// The object on which the property was invalidated.
        /// EventArgs that contains the old and new values for this property 
        private static void OnItemContainerStyleSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            ((ItemsControl) d).OnItemContainerStyleSelectorChanged((StyleSelector) e.OldValue, (StyleSelector) e.NewValue); 
        }

        /// 
        ///     This method is invoked when the ItemContainerStyleSelector property changes. 
        /// 
        /// The old value of the ItemContainerStyleSelector property. 
        /// The new value of the ItemContainerStyleSelector property. 
        protected virtual void OnItemContainerStyleSelectorChanged(StyleSelector oldItemContainerStyleSelector, StyleSelector newItemContainerStyleSelector)
        { 
            Helper.CheckStyleAndStyleSelector("ItemContainer", ItemContainerStyleProperty, ItemContainerStyleSelectorProperty, this);

            if ((_itemContainerGenerator != null) && (ItemContainerStyle == null))
            { 
                _itemContainerGenerator.Refresh();
            } 
        } 

        ///  
        ///     Returns the ItemsControl for which element is an ItemsHost.
        ///     More precisely, if element is marked by setting IsItemsHost="true"
        ///     in the style for an ItemsControl, or if element is a panel created
        ///     by the ItemsPresenter for an ItemsControl, return that ItemsControl. 
        ///     Otherwise, return null.
        ///  
        public static ItemsControl GetItemsOwner(DependencyObject element) 
        {
            ItemsControl container = null; 
            Panel panel = element as Panel;

            if (panel != null && panel.IsItemsHost)
            { 
                // see if element was generated for an ItemsPresenter
                ItemsPresenter ip = ItemsPresenter.FromPanel(panel); 
 
                if (ip != null)
                { 
                    // if so use the element whose style begat the ItemsPresenter
                    container = ip.Owner;
                }
                else 
                {
                    // otherwise use element's templated parent 
                    container = panel.TemplatedParent as ItemsControl; 
                }
            } 

            return container;
        }
 

        ///  
        ///     The DependencyProperty for the ItemsPanel property. 
        ///     Flags:              none
        ///     Default Value:      null 
        /// 
        [CommonDependencyProperty]
        public static readonly DependencyProperty ItemsPanelProperty
            = DependencyProperty.Register("ItemsPanel", typeof(ItemsPanelTemplate), typeof(ItemsControl), 
                                          new FrameworkPropertyMetadata(GetDefaultItemsPanelTemplate(),
                                                                        new PropertyChangedCallback(OnItemsPanelChanged))); 
 
        private static ItemsPanelTemplate GetDefaultItemsPanelTemplate()
        { 
            ItemsPanelTemplate template = new ItemsPanelTemplate(new FrameworkElementFactory(typeof(StackPanel)));
            template.Seal();
            return template;
        } 

        ///  
        ///     ItemsPanel is the panel that controls the layout of items. 
        ///     (More precisely, the panel that controls layout is created
        ///     from the template given by ItemsPanel.) 
        /// 
        [Bindable(false)]
        public ItemsPanelTemplate ItemsPanel
        { 
            get { return (ItemsPanelTemplate) GetValue(ItemsPanelProperty); }
            set { SetValue(ItemsPanelProperty, value); } 
        } 

        ///  
        ///     Called when ItemsPanelProperty is invalidated on "d."
        /// 
        /// The object on which the property was invalidated.
        /// EventArgs that contains the old and new values for this property 
        private static void OnItemsPanelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        { 
            ((ItemsControl) d).OnItemsPanelChanged((ItemsPanelTemplate) e.OldValue, (ItemsPanelTemplate) e.NewValue); 
        }
 
        /// 
        ///     This method is invoked when the ItemsPanel property changes.
        /// 
        /// The old value of the ItemsPanel property. 
        /// The new value of the ItemsPanel property.
        protected virtual void OnItemsPanelChanged(ItemsPanelTemplate oldItemsPanel, ItemsPanelTemplate newItemsPanel) 
        { 
            ItemContainerGenerator.OnPanelChanged();
        } 


        private static readonly DependencyPropertyKey IsGroupingPropertyKey =
            DependencyProperty.RegisterReadOnly("IsGrouping", typeof(bool), typeof(ItemsControl), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        ///  
        ///     The DependencyProperty for the IsGrouping property. 
        /// 
        public static readonly DependencyProperty IsGroupingProperty = IsGroupingPropertyKey.DependencyProperty; 

        /// 
        ///     Returns whether the control is using grouping.
        ///  
        [Bindable(false)]
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        public bool IsGrouping 
        {
            get 
            {
                return (bool)GetValue(IsGroupingProperty);
            }
        } 

        ///  
        /// The collection of GroupStyle objects that describes the display of 
        /// each level of grouping.  The entry at index 0 describes the top level
        /// groups, the entry at index 1 describes the next level, and so forth. 
        /// If there are more levels of grouping than entries in the collection,
        /// the last entry is used for the extra levels.
        /// 
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Content)] 
        public ObservableCollection GroupStyle
        { 
            get { return _groupStyle; } 
        }
 
        /// 
        /// This method is used by TypeDescriptor to determine if this property should
        /// be serialized.
        ///  
        [EditorBrowsable(EditorBrowsableState.Never)]
        public bool ShouldSerializeGroupStyle() 
        { 
            return (GroupStyle.Count > 0);
        } 

        private void OnGroupStyleChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            if (_itemContainerGenerator != null) 
            {
                _itemContainerGenerator.Refresh(); 
            } 
        }
 

        /// 
        ///     The DependencyProperty for the GroupStyleSelector property.
        ///     Flags:              none 
        ///     Default Value:      null
        ///  
        public static readonly DependencyProperty GroupStyleSelectorProperty 
            = DependencyProperty.Register("GroupStyleSelector", typeof(GroupStyleSelector), typeof(ItemsControl),
                                          new FrameworkPropertyMetadata((GroupStyleSelector)null, 
                                                                        new PropertyChangedCallback(OnGroupStyleSelectorChanged)));

        /// 
        ///     GroupStyleSelector allows the app writer to provide custom selection logic 
        ///     for a GroupStyle to apply to each group collection.
        ///  
        [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)] 
        [Bindable(true), CustomCategory("Content")]
        public GroupStyleSelector GroupStyleSelector 
        {
            get { return (GroupStyleSelector) GetValue(GroupStyleSelectorProperty); }
            set { SetValue(GroupStyleSelectorProperty, value); }
        } 

        ///  
        ///     Called when GroupStyleSelectorProperty is invalidated on "d." 
        /// 
        /// The object on which the property was invalidated. 
        /// EventArgs that contains the old and new values for this property
        private static void OnGroupStyleSelectorChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            ((ItemsControl) d).OnGroupStyleSelectorChanged((GroupStyleSelector) e.OldValue, (GroupStyleSelector) e.NewValue); 
        }
 
        ///  
        ///     This method is invoked when the GroupStyleSelector property changes.
        ///  
        /// The old value of the GroupStyleSelector property.
        /// The new value of the GroupStyleSelector property.
        protected virtual void OnGroupStyleSelectorChanged(GroupStyleSelector oldGroupStyleSelector, GroupStyleSelector newGroupStyleSelector)
        { 
            if (_itemContainerGenerator != null)
            { 
                _itemContainerGenerator.Refresh(); 
            }
        } 

        /// 
        ///     The DependencyProperty for the AlternationCount property.
        ///     Flags:              none 
        ///     Default Value:      0
        ///  
        public static readonly DependencyProperty AlternationCountProperty = 
                DependencyProperty.Register(
                        "AlternationCount", 
                        typeof(int),
                        typeof(ItemsControl),
                        new FrameworkPropertyMetadata(
                                (int)0, 
                                new PropertyChangedCallback(OnAlternationCountChanged)));
 
        ///  
        ///     AlternationCount controls the range of values assigned to the
        ///     AlternationIndex property attached to each generated container.  The 
        ///     default value 0 means "do not set AlternationIndex".  A positive
        ///     value means "assign AlternationIndex in the range [0, AlternationCount)
        ///     so that adjacent containers receive different values".
        ///  
        /// 
        ///     By referring to AlternationIndex in a trigger or binding (typically 
        ///     in the ItemContainerStyle), you can make the appearance of items 
        ///     depend on their position in the display.  For example, you can make
        ///     the background color of the items in ListBox alternate between 
        ///     blue and white.
        /// 
        [Bindable(true), CustomCategory("Content")]
        public int AlternationCount 
        {
            get { return (int) GetValue(AlternationCountProperty); } 
            set { SetValue(AlternationCountProperty, value); } 
        }
 
        /// 
        ///     Called when AlternationCountProperty is invalidated on "d."
        /// 
        private static void OnAlternationCountChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            ItemsControl ctrl = (ItemsControl) d; 
 
            int oldAlternationCount = (int) e.OldValue;
            int newAlternationCount = (int) e.NewValue; 

            ctrl.OnAlternationCountChanged(oldAlternationCount, newAlternationCount);
        }
 
        /// 
        ///     This method is invoked when the AlternationCount property changes. 
        ///  
        /// The old value of the AlternationCount property.
        /// The new value of the AlternationCount property. 
        protected virtual void OnAlternationCountChanged(int oldAlternationCount, int newAlternationCount)
        {
            ItemContainerGenerator.ChangeAlternationCount();
        } 

        private static readonly DependencyPropertyKey AlternationIndexPropertyKey = 
                    DependencyProperty.RegisterAttachedReadOnly( 
                                "AlternationIndex",
                                typeof(int), 
                                typeof(ItemsControl),
                                new FrameworkPropertyMetadata((int)0));

        ///  
        /// AlternationIndex is set on containers generated for an ItemsControl, when
        /// the ItemsControl's AlternationCount property is positive.  The AlternationIndex 
        /// lies in the range [0, AlternationCount), and adjacent containers always get 
        /// assigned different values.
        ///  
        public static readonly DependencyProperty AlternationIndexProperty =
                    AlternationIndexPropertyKey.DependencyProperty;

        ///  
        /// Static getter for the AlternationIndex attached property.
        ///  
        public static int GetAlternationIndex(DependencyObject element) 
        {
            if (element == null) 
                throw new ArgumentNullException("element");

            return (int)element.GetValue(AlternationIndexProperty);
        } 

        // internal setter for AlternationIndex.  This property is not settable by 
        // an app, only by internal code 
        internal static void SetAlternationIndex(DependencyObject d, int value)
        { 
            d.SetValue(AlternationIndexPropertyKey, value);
        }

        // internal clearer for AlternationIndex.  This property is not settable by 
        // an app, only by internal code
        internal static void ClearAlternationIndex(DependencyObject d) 
        { 
            d.ClearValue(AlternationIndexPropertyKey);
        } 

        /// 
        ///     The DependencyProperty for the IsTextSearchEnabled property.
        ///     Default Value:      false 
        /// 
        public static readonly DependencyProperty IsTextSearchEnabledProperty = 
                DependencyProperty.Register( 
                        "IsTextSearchEnabled",
                        typeof(bool), 
                        typeof(ItemsControl),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

        ///  
        ///     Whether TextSearch is enabled or not on this ItemsControl
        ///  
        public bool IsTextSearchEnabled 
        {
            get { return (bool) GetValue(IsTextSearchEnabledProperty); } 
            set { SetValue(IsTextSearchEnabledProperty, BooleanBoxes.Box(value)); }
        }

        ///  
        ///     The DependencyProperty for the IsTextSearchCaseSensitive property.
        ///     Default Value:      false 
        ///  
        public static readonly DependencyProperty IsTextSearchCaseSensitiveProperty =
                DependencyProperty.Register( 
                        "IsTextSearchCaseSensitive",
                        typeof(bool),
                        typeof(ItemsControl),
                        new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 

        ///  
        ///     Whether TextSearch is case sensitive or not on this ItemsControl 
        /// 
        public bool IsTextSearchCaseSensitive 
        {
            get { return (bool) GetValue(IsTextSearchCaseSensitiveProperty); }
            set { SetValue(IsTextSearchCaseSensitiveProperty, BooleanBoxes.Box(value)); }
        } 
        #endregion
 
        #region Mapping methods 

        /// 
        /// Return the ItemsControl that owns the given container element
        ///
        public static ItemsControl ItemsControlFromItemContainer(DependencyObject container)
        { 
            UIElement ui = container as UIElement;
            if (ui == null) 
                return null; 

            // ui appeared in items collection 
            ItemsControl ic = LogicalTreeHelper.GetParent(ui) as ItemsControl;
            if (ic != null)
            {
                // this is the right ItemsControl as long as the item 
                // is (or is eligible to be) its own container
                IGeneratorHost host = ic as IGeneratorHost; 
                if (host.IsItemItsOwnContainer(ui)) 
                    return ic;
                else 
                    return null;
            }

            ui = VisualTreeHelper.GetParent(ui) as UIElement; 

            return ItemsControl.GetItemsOwner(ui); 
        } 

        /// 
        /// Return the container that owns the given element.  If itemsControl
        /// is not null, return a container that belongs to the given ItemsControl.
        /// If itemsControl is null, return the closest container belonging to
        /// any ItemsControl.  Return null if no such container exists. 
        ///
        public static DependencyObject ContainerFromElement(ItemsControl itemsControl, DependencyObject element) 
        { 
            if (element == null)
                throw new ArgumentNullException("element"); 

            // if the element is itself the desired container, return it
            if (IsContainerForItemsControl(element, itemsControl))
            { 
                return element;
            } 
 
            // start the tree walk at the element's parent
            FrameworkObject fo = new FrameworkObject(element); 
            fo.Reset(fo.GetPreferVisualParent(true).DO);

            // walk up, stopping when we reach the desired container
            while (fo.DO != null) 
            {
                if (IsContainerForItemsControl(fo.DO, itemsControl)) 
                { 
                    break;
                } 

                fo.Reset(fo.PreferVisualParent.DO);
            }
 
            return fo.DO;
        } 
 
        ///
        /// Return the container belonging to the current ItemsControl that owns 
        /// the given container element.  Return null if no such container exists.
        ///
        public DependencyObject ContainerFromElement(DependencyObject element)
        { 
            return ContainerFromElement(this, element);
        } 
 
        // helper method used by ContainerFromElement
        private static bool IsContainerForItemsControl(DependencyObject element, ItemsControl itemsControl) 
        {
            // is the element a container?
            if (element.ContainsValue(ItemContainerGenerator.ItemForItemContainerProperty))
            { 
                // does the element belong to the itemsControl?
                if (itemsControl == null || itemsControl == ItemsControlFromItemContainer(element)) 
                { 
                    return true;
                } 
            }

            return false;
        } 

        #endregion Mapping methods 
 
        #region IAddChild
 
        ///
        /// Called to Add the object as a Child.
        ///
        /// 
        /// Object to add as a child
        /// 
        void IAddChild.AddChild(Object value) 
        {
            AddChild(value); 
        }

        /// 
        ///  Add an object child to this control 
        /// 
        protected virtual void AddChild(object value) 
        { 
            Items.Add(value);
        } 

        ///
        /// Called when text appears under the tag in markup
        /// 
        ///
        /// Text to Add to the Object 
        /// 
        void IAddChild.AddText(string text)
        { 
            AddText(text);
        }

        ///  
        ///  Add a text string to this control
        ///  
        protected virtual void AddText(string text) 
        {
            Items.Add(text); 
        }

        #endregion
 
        #region IGeneratorHost
 
        //----------------------------------------------------- 
        //
        //  Interface - IGeneratorHost 
        //
        //-----------------------------------------------------

        ///  
        /// The view of the data
        ///  
        ItemCollection IGeneratorHost.View 
        {
            get { return Items; } 
        }

        /// 
        /// Return true if the item is (or is eligible to be) its own ItemContainer 
        /// 
        bool IGeneratorHost.IsItemItsOwnContainer(object item) 
        { 
            return IsItemItsOwnContainerOverride(item);
        } 

        /// 
        /// Return the element used to display the given item
        ///  
        DependencyObject IGeneratorHost.GetContainerForItem(object item)
        { 
            DependencyObject container; 

            // use the item directly, if possible (bug 870672) 
            if (IsItemItsOwnContainerOverride(item))
                container = item as DependencyObject;
            else
                container = GetContainerForItemOverride(); 

            // the container might have a parent from a previous 
            // generation (bug 873118).  If so, clean it up before using it again. 
            //
            // Note: This assumes the container is about to be added to a new parent, 
            // according to the ItemsControl/Generator/Container pattern.
            // If someone calls the generator and doesn't add the container to
            // a visual parent, unexpected things might happen.
            Visual visual = container as Visual; 
            if (visual != null)
            { 
                Visual parent = VisualTreeHelper.GetParent(visual) as Visual; 
                if (parent != null)
                { 
                    Invariant.Assert(parent is FrameworkElement, SR.Get(SRID.ItemsControl_ParentNotFrameworkElement));
                    Panel p = parent as Panel;
                    if (p != null && (visual is UIElement))
                    { 
                        p.Children.RemoveNoVerify((UIElement)visual);
                    } 
                    else 
                    {
                        ((FrameworkElement)parent).TemplateChild = null; 
                    }
                }
            }
 
            return container;
        } 
 
        /// 
        /// Prepare the element to act as the ItemContainer for the corresponding item. 
        /// 
        void IGeneratorHost.PrepareItemContainer(DependencyObject container, object item)
        {
            // GroupItems are special - their information comes from a different place 
            GroupItem groupItem = container as GroupItem;
            if (groupItem != null) 
            { 
                groupItem.PrepareItemContainer(item);
                return; 
            }

            if (ShouldApplyItemContainerStyle(container, item))
            { 
                // apply the ItemContainer style (if any)
                ApplyItemContainerStyle(container, item); 
            } 

            // forward ItemTemplate, et al. 
            PrepareContainerForItemOverride(container, item);

            // set up the binding group
            if (!Helper.HasUnmodifiedDefaultValue(this, ItemBindingGroupProperty) && 
                Helper.HasUnmodifiedDefaultOrInheritedValue(container, FrameworkElement.BindingGroupProperty))
            { 
                BindingGroup itemBindingGroup = ItemBindingGroup; 
                BindingGroup containerBindingGroup =
                    (itemBindingGroup != null)  ? new BindingGroup(itemBindingGroup) 
                                                : null;
                container.SetValue(FrameworkElement.BindingGroupProperty, containerBindingGroup);
            }
 
            if (container == item && TraceData.IsEnabled)
            { 
                // issue a message if there's an ItemTemplate(Selector) for "direct" items 
                // The ItemTemplate isn't used, which may confuse the user (bug 991101).
                if (ItemTemplate != null || ItemTemplateSelector != null) 
                {
                    TraceData.Trace(TraceEventType.Error, TraceData.ItemTemplateForDirectItem, AvTrace.TypeName(item));
                }
            } 

 
            // 
            // ItemValueStorage:  restore saved values for this item onto the new container
            // 
            // Note:  ItemValueStorage for now is only for TreeView.  In the future we could allow other types to use it.
            //
            if ((this is TreeViewItem || this is TreeView) && IsVirtualizing)
            { 
                SetItemValuesOnContainer(container, item, ItemValueStorageIndices);
            } 
        } 

        ///  
        /// Undo any initialization done on the element during GetContainerForItem and PrepareItemContainer
        /// 
        void IGeneratorHost.ClearContainerForItem(DependencyObject container, object item)
        { 
            // This method no longer does most of the work it used to (bug 1445288).
            // It is called when a container is removed from the tree;  such a 
            // container will be GC'd soon, so there's no point in changing 
            // its properties.
            // 
            // We still call the override method, to give subclasses a chance
            // to clean up anything they may have done during Prepare (bug 1561206).

            GroupItem groupItem = container as GroupItem; 
            if (groupItem == null)
            { 
                ClearContainerForItemOverride(container, item); 
            }
            else 
            {
                // GroupItems are special - their information comes from a different place
                // Recursively clear the sub-generators, so that ClearContainerForItemOverride
                // is called on the bottom-level containers. 
                IItemContainerGenerator iicg = groupItem.Generator as IItemContainerGenerator;
                if (iicg != null) 
                { 
                    iicg.RemoveAll();
                } 
            }


            // 
            // ItemValueStorage:  save off values for this container if we're a virtualizing TreeView.
            // 
 
            //
            // Right now we have a hard-coded list of DPs we want to save off.  In the future we could provide a 'register' API 
            // so that each ItemsControl could decide what DPs to save on its containers. Maybe we define a virtual method to
            // retrieve a list of DPs the type is interested in.  Alternatively we could have the contract
            // be that ItemsControls use the ItemStorageService inside their ClearContainerForItemOverride by calling into StoreItemValues.
            // 

            // Would it be better to simply call the virtual and have each type decide which DPs it wants to save?  Doing these checks 
            // once per item is probably expensive. 
            if ((this is TreeViewItem || this is TreeView) && IsVirtualizing)
            { 

                // Tell the container to clear off all its containers.  This will cause this method to be called
                // recursively down the tree, allowing all descendent data to be stored before we save off
                // the ItemValueStorage DP for this container. 

                ItemsControl containerAsIC = container as ItemsControl; 
                if (containerAsIC != null && VirtualizingStackPanel.GetIsVirtualizing(container) == true) 
                {
                    VirtualizingStackPanel itemsHost = containerAsIC.ItemsHost as VirtualizingStackPanel; 

                    if (itemsHost != null)
                    {
                        itemsHost.ClearAllContainers(containerAsIC); 
                    }
                } 
 
                StoreItemValues(container, item, ItemValueStorageIndices);
            } 
        }


 
        /// 
        /// Determine if the given element was generated for this host as an ItemContainer. 
        ///  
        bool IGeneratorHost.IsHostForItemContainer(DependencyObject container)
        { 
            // If ItemsControlFromItemContainer can determine who owns the element,
            // use its decision.
            ItemsControl ic = ItemsControlFromItemContainer(container);
            if (ic != null) 
                return (ic == this);
 
            // If the element is in my items view, and if it can be its own ItemContainer, 
            // it's mine.  Contains may be expensive, so we avoid calling it in cases
            // where we already know the answer - namely when the element has a 
            // logical parent (ItemsControlFromItemContainer handles this case).  This
            // leaves only those cases where the element belongs to my items
            // without having a logical parent (e.g. via ItemsSource) and without
            // having been generated yet. HasItem indicates if anything has been generated. 
            DependencyObject parent = LogicalTreeHelper.GetParent(container);
            if (parent == null) 
            { 
                return IsItemItsOwnContainerOverride(container) &&
                    HasItems && Items.Contains(container); 
            }

            // Otherwise it's not mine
            return false; 
        }
 
        ///  
        /// Return the GroupStyle (if any) to use for the given group at the given level.
        ///  
        GroupStyle IGeneratorHost.GetGroupStyle(CollectionViewGroup group, int level)
        {
            GroupStyle result = null;
 
            // a. Use global selector
            if (GroupStyleSelector != null) 
            { 
                result = GroupStyleSelector(group, level);
            } 

            // b. lookup in GroupStyle list
            if (result == null)
            { 
                // use last entry for all higher levels
                if (level >= GroupStyle.Count) 
                { 
                    level = GroupStyle.Count - 1;
                } 

                if (level >= 0)
                {
                    result = GroupStyle[level]; 
                }
            } 
 
            return result;
        } 

        /// 
        /// Communicates to the host that the generator is using grouping.
        ///  
        void IGeneratorHost.SetIsGrouping(bool isGrouping)
        { 
            SetValue(IsGroupingPropertyKey, BooleanBoxes.Box(isGrouping)); 
        }
 
        /// 
        /// The AlternationCount
        /// 
        int IGeneratorHost.AlternationCount { get { return AlternationCount; } } 

        #endregion IGeneratorHost 
 
        #region ISupportInitialize
        ///  
        ///     Initialization of this element is about to begin
        /// 
        public override void BeginInit()
        { 
            base.BeginInit();
 
            if (_items != null) 
            {
                _items.BeginInit(); 
            }
        }

        ///  
        ///     Initialization of this element has completed
        ///  
        public override void EndInit() 
        {
            if (IsInitPending) 
            {
                if (_items != null)
                {
                    _items.EndInit(); 
                }
 
                base.EndInit(); 
            }
        } 

        private bool IsInitPending
        {
            get 
            {
                return ReadInternalFlag(InternalFlags.InitPending); 
            } 
        }
 
        #endregion

        #region Protected Methods
 
        /// 
        /// Return true if the item is (or should be) its own item container 
        ///  
        protected virtual bool IsItemItsOwnContainerOverride(object item)
        { 
            return (item is UIElement);
        }

        ///  Create or identify the element used to display the given item.  
        protected virtual DependencyObject GetContainerForItemOverride()
        { 
            return new ContentPresenter(); 
        }
 
        /// 
        /// Prepare the element to display the item.  This may involve
        /// applying styles, setting bindings, etc.
        ///  
        protected virtual void PrepareContainerForItemOverride(DependencyObject element, object item)
        { 
            // Each type of "ItemContainer" element may require its own initialization. 
            // We use explicit polymorphism via internal methods for this.
            // 
            // Another way would be to define an interface IGeneratedItemContainer with
            // corresponding virtual "core" methods.  Base classes (ContentControl,
            // ItemsControl, ContentPresenter) would implement the interface
            // and forward the work to subclasses via the "core" methods. 
            //
            // While this is better from an OO point of view, and extends to 
            // 3rd-party elements used as containers, it exposes more public API. 
            // Management considers this undesirable, hence the following rather
            // inelegant code. 

            HeaderedContentControl hcc;
            ContentControl cc;
            ContentPresenter cp; 
            ItemsControl ic;
            HeaderedItemsControl hic; 
 
            if ((hcc = element as HeaderedContentControl) != null)
            { 
                hcc.PrepareHeaderedContentControl(item, ItemTemplate, ItemTemplateSelector, ItemStringFormat);
            }
            else if ((cc = element as ContentControl) != null)
            { 
                cc.PrepareContentControl(item, ItemTemplate, ItemTemplateSelector, ItemStringFormat);
            } 
            else if ((cp = element as ContentPresenter) != null) 
            {
                cp.PrepareContentPresenter(item, ItemTemplate, ItemTemplateSelector, ItemStringFormat); 
            }
            else if ((hic = element as HeaderedItemsControl) != null)
            {
                hic.PrepareHeaderedItemsControl(item, this); 
            }
            else if ((ic = element as ItemsControl) != null) 
            { 
                if (ic != this)
                { 
                    ic.PrepareItemsControl(item, this);
                }
            }
        } 

        ///  
        /// Undo the effects of PrepareContainerForItemOverride. 
        /// 
        protected virtual void ClearContainerForItemOverride(DependencyObject element, object item) 
        {
            HeaderedContentControl hcc;
            ContentControl cc;
            ContentPresenter cp; 
            ItemsControl ic;
            HeaderedItemsControl hic; 
 
            if ((hcc = element as HeaderedContentControl) != null)
            { 
                hcc.ClearHeaderedContentControl(item);
            }
            else if ((cc = element as ContentControl) != null)
            { 
                cc.ClearContentControl(item);
            } 
            else if ((cp = element as ContentPresenter) != null) 
            {
                cp.ClearContentPresenter(item); 
            }
            else if ((hic = element as HeaderedItemsControl) != null)
            {
                hic.ClearHeaderedItemsControl(item); 
            }
            else if ((ic = element as ItemsControl) != null) 
            { 
                if (ic != this)
                { 
                    ic.ClearItemsControl(item);
                }
            }
        } 

        ///  
        ///     Called when a TextInput event is received. 
        /// 
        ///  
        protected override void OnTextInput(TextCompositionEventArgs e)
        {
            base.OnTextInput(e);
 
            // Only handle text from ourselves or an item container
            if (!String.IsNullOrEmpty(e.Text) && IsTextSearchEnabled && 
                (e.OriginalSource == this || ItemsControlFromItemContainer(e.OriginalSource as DependencyObject) == this)) 
            {
                TextSearch instance = TextSearch.EnsureInstance(this); 

                if (instance != null)
                {
                    instance.DoSearch(e.Text); 
                    // Note: we always want to handle the event to denote that we
                    // actually did something.  We wouldn't want an AccessKey 
                    // to get invoked just because there wasn't a match here. 
                    e.Handled = true;
                } 
            }
        }

        ///  
        ///     Called when a KeyDown event is received.
        ///  
        ///  
        protected override void OnKeyDown(KeyEventArgs e)
        { 
            base.OnKeyDown(e);
            if (IsTextSearchEnabled)
            {
                // If the pressed the backspace key, delete the last character 
                // in the TextSearch current prefix.
                if (e.Key == Key.Back) 
                { 
                    TextSearch instance = TextSearch.EnsureInstance(this);
 
                    if (instance != null)
                    {
                        instance.DeleteLastCharacter();
                    } 
                }
            } 
        } 

        internal override void OnTemplateChangedInternal(FrameworkTemplate oldTemplate, FrameworkTemplate newTemplate) 
        {
            // Forget about the old ItemsHost we had when the style changes
            _itemsHost = null;
            _scrollHost = null; 
            WriteControlFlag(ControlBoolFlags.ScrollHostValid, false);
 
            base.OnTemplateChangedInternal(oldTemplate, newTemplate); 
        }
 
        /// 
        /// Determine whether the ItemContainerStyle/StyleSelector should apply to the container
        /// 
        /// true if the ItemContainerStyle should apply to the item 
        protected virtual bool ShouldApplyItemContainerStyle(DependencyObject container, object item)
        { 
            return true; 
        }
 
        #endregion

        //------------------------------------------------------
        // 
        //  Internal methods
        // 
        //----------------------------------------------------- 

        #region Internal Methods 

        /// 
        /// Prepare to display the item.
        ///  
        internal void PrepareItemsControl(object item, ItemsControl parentItemsControl)
        { 
            if (item != this) 
            {
                // copy templates and styles from parent ItemsControl 
                DataTemplate itemTemplate = parentItemsControl.ItemTemplate;
                DataTemplateSelector itemTemplateSelector = parentItemsControl.ItemTemplateSelector;
                string itemStringFormat = parentItemsControl.ItemStringFormat;
                Style itemContainerStyle = parentItemsControl.ItemContainerStyle; 
                StyleSelector itemContainerStyleSelector = parentItemsControl.ItemContainerStyleSelector;
                int alternationCount = parentItemsControl.AlternationCount; 
                BindingGroup itemBindingGroup = parentItemsControl.ItemBindingGroup; 

                if (itemTemplate != null) 
                {
                    SetValue(ItemTemplateProperty, itemTemplate);
                }
                if (itemTemplateSelector != null) 
                {
                    SetValue(ItemTemplateSelectorProperty, itemTemplateSelector); 
                } 
                if (itemStringFormat != null &&
                    Helper.HasDefaultValue(this, ItemStringFormatProperty)) 
                {
                    SetValue(ItemStringFormatProperty, itemStringFormat);
                }
                if (itemContainerStyle != null && 
                    Helper.HasDefaultValue(this, ItemContainerStyleProperty))
                { 
                    SetValue(ItemContainerStyleProperty, itemContainerStyle); 
                }
                if (itemContainerStyleSelector != null && 
                    Helper.HasDefaultValue(this, ItemContainerStyleSelectorProperty))
                {
                    SetValue(ItemContainerStyleSelectorProperty, itemContainerStyleSelector);
                } 
                if (alternationCount != 0 &&
                    Helper.HasDefaultValue(this, AlternationCountProperty)) 
                { 
                    SetValue(AlternationCountProperty, alternationCount);
                } 
                if (itemBindingGroup != null &&
                    Helper.HasDefaultValue(this, ItemBindingGroupProperty))
                {
                    SetValue(ItemBindingGroupProperty, itemBindingGroup); 
                }
            } 
        } 

        ///  
        /// Undo the effect of PrepareItemsControl.
        /// 
        internal void ClearItemsControl(object item)
        { 
            if (item != this)
            { 
                // nothing to do 
            }
        } 

        /// 
        /// Bringing the item passed as arg into view. If item is virtualized it will become realized.
        ///  
        /// 
        ///  
        internal object OnBringItemIntoView(object arg) 
        {
            FrameworkElement element = ItemContainerGenerator.ContainerFromItem(arg) as FrameworkElement; 
            if (element != null)
            {
                element.BringIntoView();
            } 
            else if (!IsGrouping && Items.Contains(arg))
            { 
                // We might be virtualized, try to de-virtualize the item. 
                // Note: There is opportunity here to make a public OM.
 
                VirtualizingPanel itemsHost = ItemsHost as VirtualizingPanel;
                if (itemsHost != null)
                {
                    itemsHost.BringIndexIntoView(Items.IndexOf(arg)); 
                }
            } 
 
            return null;
        } 

        internal Panel ItemsHost
        {
            get 
            {
                return _itemsHost; 
            } 
            set { _itemsHost = value; }
        } 


        internal bool IsVirtualizing
        { 
            get
            { 
                return VirtualizingStackPanel.GetIsVirtualizing(this); 
            }
        } 

        #region Keyboard Navigation

        internal void NavigateByLine(FocusNavigationDirection direction, ItemNavigateArgs itemNavigateArgs) 
        {
            NavigateByLine(FocusedItem, direction, itemNavigateArgs); 
        } 

        internal void NavigateByLine(object startingItem, FocusNavigationDirection direction, ItemNavigateArgs itemNavigateArgs) 
        {
            if (ItemsHost == null)
            {
                return; 
            }
 
            // If the focused item has been scrolled out of view and they want to 
            // start navigating again, scroll it back into view.
            if (startingItem != null && !IsOnCurrentPage(startingItem, direction)) 
            {
                MakeVisible(Items.IndexOf(startingItem));
                // Wait for layout
                ItemsHost.UpdateLayout(); 
            }
 
            // When we get here if startingItem is non-null, it must be on the visible page. 
            NavigateByLineInternal(startingItem, direction, itemNavigateArgs);
        } 

        private void NavigateByLineInternal(object startingItem, FocusNavigationDirection direction, ItemNavigateArgs itemNavigateArgs)
        {
            // If there is no starting item, just navigate to the first item. 
            if (startingItem == null)
            { 
                NavigateToStart(itemNavigateArgs); 
            }
            else 
            {
                FrameworkElement startingElement = null;
                FrameworkElement nextElement = null;
 
                startingElement = ItemContainerGenerator.ContainerFromItem(startingItem) as FrameworkElement;
                // If the container isn't there, it might have been degenerated or 
                // it might have been scrolled out of view.  Either way, we 
                // should start navigation from the ItemsHost b/c we know it
                // is visible. 
                // The generator could have given us an element which isn't
                // actually visually connected.  In this case we should use
                // the ItemsHost as well.
                if (startingElement == null || !ItemsHost.IsAncestorOf(startingElement)) 
                {
                    // Bug 991220 makes it so that we have to start from the ScrollHost. 
                    // If we try to start from the ItemsHost it will always skip the first item. 
                    startingElement = ScrollHost;
                } 

                nextElement = KeyboardNavigation.Current.PredictFocusedElement(startingElement, direction) as FrameworkElement;

                // We can only navigate there if the target element is in the items host. 
                if ((nextElement != null) && (ItemsHost.IsAncestorOf(nextElement)))
                { 
                    object nextItem = GetEncapsulatingItem(nextElement); 

                    if (nextItem != DependencyProperty.UnsetValue) 
                    {
                        NavigateToItem(nextItem, itemNavigateArgs);
                    }
                } 
            }
        } 
 
        internal void NavigateByPage(FocusNavigationDirection direction, ItemNavigateArgs itemNavigateArgs)
        { 
            NavigateByPage(FocusedItem, direction, itemNavigateArgs);
        }

        internal void NavigateByPage(object startingItem, FocusNavigationDirection direction, ItemNavigateArgs itemNavigateArgs) 
        {
            if (ItemsHost == null) 
            { 
                return;
            } 

            // If the focused item has been scrolled out of view and they want to
            // start navigating again, scroll it back into view.
            if (startingItem != null && !IsOnCurrentPage(startingItem, direction)) 
            {
                while (MakeVisible(Items.IndexOf(startingItem))) 
                { 
                    double oldHorizontalOffset = ScrollHost.HorizontalOffset;
                    double oldVerticalOffset = ScrollHost.VerticalOffset; 

                    ItemsHost.UpdateLayout();

                    // If offset does not change - exit the loop 
                    if (DoubleUtil.AreClose(oldHorizontalOffset, ScrollHost.HorizontalOffset) &&
                        DoubleUtil.AreClose(oldVerticalOffset, ScrollHost.VerticalOffset)) 
                        break; 
                }
            } 

            NavigateByPageInternal(startingItem, direction, itemNavigateArgs);
        }
 
        private void NavigateByPageInternal(object startingItem, FocusNavigationDirection direction, ItemNavigateArgs itemNavigateArgs)
        { 
            // Move to the last guy on the page if we're not already there. 
            if (startingItem == null)
            { 
                NavigateToFirstItemOnCurrentPage(startingItem, direction, itemNavigateArgs);
            }
            else
            { 
                // See if the currently focused guy is the first or last one one the page
                int firstIndex; 
                object first = GetFirstItemOnCurrentPage(startingItem, direction, out firstIndex); 

                if (startingItem.Equals(first)) 
                {
                    // Page in that direction
                    bool navigateAfterMeasure = false;
 
                    if (ScrollHost != null)
                    { 
                        switch (direction) 
                        {
                            case FocusNavigationDirection.Up: 
                                if (IsLogicalHorizontal)
                                {
                                    ScrollHost.PageLeft();
                                } 
                                else
                                { 
                                    ScrollHost.PageUp(); 
                                }
 
                                navigateAfterMeasure = true;
                                break;

                            case FocusNavigationDirection.Down: 
                                if (IsLogicalHorizontal)
                                { 
                                    ScrollHost.PageRight(); 
                                }
                                else 
                                {
                                    ScrollHost.PageDown();
                                }
 
                                navigateAfterMeasure = true;
                                break; 
                        } 
                    }
 
                    // After measure we should focus the first guy on the page
                    if (navigateAfterMeasure)
                    {
                        if (ItemsHost != null) 
                        {
                            ItemsHost.UpdateLayout(); 
                            NavigateToFirstItemOnCurrentPage(startingItem, direction, itemNavigateArgs); 
                        }
                    } 
                }
                else
                {
                    // The currently focused guy is not the first on the page, so move there 
                    if (first != DependencyProperty.UnsetValue)
                    { 
                        NavigateToItem(first, firstIndex, itemNavigateArgs); 
                    }
                } 
            }
        }

        internal void NavigateToStart(ItemNavigateArgs itemNavigateArgs) 
        {
            if (HasItems) 
            { 
                int foundIndex;
                object item = FindFocusable(0, 1, out foundIndex); 
                NavigateToItem(item, foundIndex, itemNavigateArgs);
            }
        }
 
        internal void NavigateToEnd(ItemNavigateArgs itemNavigateArgs)
        { 
            if (HasItems) 
            {
                int foundIndex; 
                object item = FindFocusable(Items.Count - 1, -1, out foundIndex);
                NavigateToItem(item, foundIndex, itemNavigateArgs);
            }
        } 

        internal void NavigateToItem(object item, ItemNavigateArgs itemNavigateArgs) 
        { 
            NavigateToItem(item, -1, itemNavigateArgs, false /* alwaysAtTopOfViewport */);
        } 

        internal void NavigateToItem(object item, int itemIndex, ItemNavigateArgs itemNavigateArgs)
        {
            NavigateToItem(item, itemIndex, itemNavigateArgs, false /* alwaysAtTopOfViewport */); 
        }
 
        internal void NavigateToItem(object item, ItemNavigateArgs itemNavigateArgs, bool alwaysAtTopOfViewport) 
        {
            NavigateToItem(item, -1, itemNavigateArgs, alwaysAtTopOfViewport); 
        }

        private void NavigateToItem(object item, int elementIndex, ItemNavigateArgs itemNavigateArgs, bool alwaysAtTopOfViewport)
        { 
            //
 
            // Perhaps the container isn't generated yet.  In this case we try to shift the view, 
            // wait for measure, and then call it again.
            if (item == DependencyProperty.UnsetValue) 
            {
                return;
            }
 
            if (elementIndex == -1)
            { 
                elementIndex = Items.IndexOf(item); 
                if (elementIndex == -1)
                    return; 
            }

            while (MakeVisible(elementIndex, alwaysAtTopOfViewport, false /* alignMinorAxisToo */))
            { 
                // The above operations to change VerticalOffset might have invalidated measure.
                // Try again after measure. 
                Debug.Assert(ItemsHost != null); 

 
                double oldHorizontalOffset = ScrollHost.HorizontalOffset;
                double oldVerticalOffset = ScrollHost.VerticalOffset;

                ItemsHost.UpdateLayout(); 

                // If offset does not change - exit the loop 
                if (DoubleUtil.AreClose(oldHorizontalOffset, ScrollHost.HorizontalOffset) && 
                    DoubleUtil.AreClose(oldVerticalOffset, ScrollHost.VerticalOffset))
                    break; 
            }

            FocusItem(item, itemNavigateArgs);
        } 

        private object FindFocusable(int startIndex, int direction, out int foundIndex) 
        { 
            // HasItems may be wrong when underlying collection does not notify, but this function
            // only cares about what's been generated and is consistent with ItemsControl state. 
            if (HasItems)
            {
                int count = Items.Count;
                for (; startIndex >= 0 && startIndex < count; startIndex += direction) 
                {
                    FrameworkElement container = ItemContainerGenerator.ContainerFromIndex(startIndex) as FrameworkElement; 
 
                    // If the UI is non-null it must meet some minimum requirements to consider it for
                    // navigation (focusable, enabled).  If it has no UI we can make no judgements about it 
                    // at this time, so it is navigable.
                    if (container == null || Keyboard.IsFocusable(container))
                    {
                        foundIndex = startIndex; 
                        return Items[startIndex];
                    } 
                } 
            }
 
            foundIndex = -1;
            return null;
        }
 
        private bool MakeVisible(int index)
        { 
            return MakeVisible(index, false /* alwaysAtTopOfViewport */, false /* alignMinorAxisToo */); 
        }
 
        // Shifts the viewport to make the given index visible.
        // Returns true if the viewport shifted.
        internal bool MakeVisible(int index, bool alwaysAtTopOfViewport, bool alignMinorAxisToo)
        { 
            if (index == -1) return false;
 
            if (ScrollHost != null) 
            {
                bool offsetChanged = false; 

                double initialHorizontalOffset = ScrollHost.HorizontalOffset;
                double initialVerticalOffset = ScrollHost.VerticalOffset;
 
                double newHorizontalOffset = initialHorizontalOffset;
                double newVerticalOffset = initialVerticalOffset; 
 
                if (IsLogicalVertical)
                { 
                    if (alwaysAtTopOfViewport)
                    {
                        newVerticalOffset = index;
                    } 
                    else
                    { 
                        // First check that the bottom is visible 
                        if (DoubleUtil.GreaterThan(index + 1, initialVerticalOffset + ScrollHost.ViewportHeight))
                        { 
                            newVerticalOffset = Math.Max(0.0, index + 1 - ScrollHost.ViewportHeight);
                        }

                        // Next make sure that the top is visible 
                        if (DoubleUtil.LessThan(index, initialVerticalOffset))
                        { 
                            newVerticalOffset = index; 
                        }
                    } 

                    if (alignMinorAxisToo)
                    {
                        newHorizontalOffset = 0; 
                    }
 
                    if (!DoubleUtil.AreClose(initialHorizontalOffset, newHorizontalOffset)) 
                    {
                        ScrollHost.ScrollToHorizontalOffset(newHorizontalOffset); 
                        offsetChanged = true;
                    }

                    if (!DoubleUtil.AreClose(initialVerticalOffset, newVerticalOffset)) 
                    {
                        ScrollHost.ScrollToVerticalOffset(newVerticalOffset); 
                        offsetChanged = true; 
                    }
                } 
                else if (IsLogicalHorizontal)
                {
                    if (alwaysAtTopOfViewport)
                    { 
                        newHorizontalOffset = index;
                    } 
                    else 
                    {
                        // First check that the bottom is visible 
                        if (DoubleUtil.GreaterThan(index + 1, initialHorizontalOffset + ScrollHost.ViewportWidth))
                        {
                            newHorizontalOffset = Math.Max(0.0, index + 1 - ScrollHost.ViewportWidth);
                        } 

                        // Next make sure that the top is visible 
                        if (DoubleUtil.LessThan(index, initialHorizontalOffset)) 
                        {
                            newHorizontalOffset = index; 
                        }
                    }

                    if (alignMinorAxisToo) 
                    {
                        newVerticalOffset = 0; 
                    } 

                    if (!DoubleUtil.AreClose(initialHorizontalOffset, newHorizontalOffset)) 
                    {
                        ScrollHost.ScrollToHorizontalOffset(newHorizontalOffset);
                        offsetChanged = true;
                    } 

                    if (!DoubleUtil.AreClose(initialVerticalOffset, newVerticalOffset)) 
                    { 
                        ScrollHost.ScrollToVerticalOffset(newVerticalOffset);
                        offsetChanged = true; 
                    }
                }
                else
                { 
                    FrameworkElement container = ItemContainerGenerator.ContainerFromIndex(index) as FrameworkElement;
                    if (container != null) 
                    { 
                        container.BringIntoView();
                        offsetChanged = !DoubleUtil.AreClose(initialHorizontalOffset, ScrollHost.HorizontalOffset) || 
                                        !DoubleUtil.AreClose(initialVerticalOffset, ScrollHost.VerticalOffset);
                    }
                }
 
                return offsetChanged;
            } 
 
            return false;
        } 

        private void NavigateToFirstItemOnCurrentPage(object startingItem, FocusNavigationDirection direction, ItemNavigateArgs itemNavigateArgs)
        {
            int foundIndex; 
            object firstItem = GetFirstItemOnCurrentPage(startingItem, direction, out foundIndex);
 
            if (firstItem != DependencyProperty.UnsetValue) 
            {
                FocusItem(firstItem, itemNavigateArgs); 
            }
        }

        private object GetFirstItemOnCurrentPage(object startingItem, FocusNavigationDirection direction, out int foundIndex) 
        {
            Debug.Assert(direction == FocusNavigationDirection.Up || direction == FocusNavigationDirection.Down, "Can only get the first item on a page using North or South"); 
            foundIndex = -1; 

            // 
            if (IsLogicalVertical)
            {
                if (direction == FocusNavigationDirection.Up)
                { 
                    return FindFocusable((int)ScrollHost.VerticalOffset, 1, out foundIndex);
                } 
                else // if (direction == FocusNavigationDirection.Down) 
                {
                    return FindFocusable((int)(ScrollHost.VerticalOffset + ScrollHost.ViewportHeight - 1), -1, out foundIndex); 
                }
            }
            else if (IsLogicalHorizontal)
            { 
                if (direction == FocusNavigationDirection.Up)
                { 
                    return FindFocusable((int)ScrollHost.HorizontalOffset, 1, out foundIndex); 
                }
                else // if (direction == FocusNavigationDirection.Down) 
                {
                    return FindFocusable((int)(ScrollHost.HorizontalOffset + ScrollHost.ViewportWidth - 1), -1, out foundIndex);
                }
            } 

            // We assume we're physically scrolling in both directions now. 
            FrameworkElement startElement = ItemContainerGenerator.ContainerFromItem(startingItem) as FrameworkElement; 
            FrameworkElement currentElement = startElement;
            FrameworkElement previousElement = null; 
            if (startElement != null)
            {
                // If the focused guy isn't on the page, try to move until we are on the page.
                // ISSUE: KeyboardNavigation needs to incorporate this logic instead this workaround. 
                while (currentElement != null && !IsOnCurrentPage(currentElement, direction))
                { 
                    previousElement = currentElement; 
                    currentElement = KeyboardNavigation.Current.PredictFocusedElement(currentElement, direction) as FrameworkElement;
                } 

                while (currentElement != null && IsOnCurrentPage(currentElement, direction))
                {
                    previousElement = currentElement; 
                    currentElement = KeyboardNavigation.Current.PredictFocusedElement(currentElement, direction) as FrameworkElement;
                } 
 
                return GetEncapsulatingItem(previousElement);
            } 

            return null;
        }
 
        /// 
        /// Determines if the given item is on the current visible page. 
        ///  
        private bool IsOnCurrentPage(object item, FocusNavigationDirection axis)
        { 
            FrameworkElement container = ItemContainerGenerator.ContainerFromItem(item) as FrameworkElement;

            if (container == null)
            { 
                return false;
            } 
 
            return IsOnCurrentPage(container, axis, false);
        } 

        private bool IsOnCurrentPage(FrameworkElement element, FocusNavigationDirection axis)
        {
            return IsOnCurrentPage(element, axis, false); 
        }
 
        ///  
        /// Determines if the given element is on the current visible page.
        /// The element must be completely on the page on the given axis, but need 
        /// not be completely contained on the page in the perpendicular axis.
        /// For example, if axis == North, then the element's Top and Bottom must
        /// be completely contained on the page.
        ///  
        private bool IsOnCurrentPage(FrameworkElement element, FocusNavigationDirection axis, bool fullyVisible)
        { 
            // NOTE: When ScrollHost is non-null, we use ScrollHost instead of 
            //       ItemsHost because ItemsHost in the physically scrolling
            //       case will just have its layout offset shifted, and all 
            //       items will always be within the bounding box of the ItemsHost,
            //       and we want to know if you can actually see the element.
            FrameworkElement viewPort = ScrollHost;
            if (viewPort == null) 
            {
                viewPort = ItemsHost; 
            } 

            // If there's no ScrollHost or ItemsHost, the element is not on the page 
            if (viewPort == null)
            {
                return false;
            } 

            if (element == null || !viewPort.IsAncestorOf(element)) 
            { 
                return false;
            } 

            Rect viewPortBounds = new Rect(new Point(), viewPort.RenderSize);
            Rect elementBounds = new Rect(new Point(), element.RenderSize);
            elementBounds = element.TransformToAncestor(viewPort).TransformBounds(elementBounds); 

            // Return true if the element is completely contained within the page along the given axis. 
 
            if (fullyVisible)
            { 
                return viewPortBounds.Contains(elementBounds);
            }
            else
            { 
                if (axis == FocusNavigationDirection.Up || axis == FocusNavigationDirection.Down)
                { 
                    // Check that the element's Top/Bottom are inside the viewport's top and bottom 
                    if (DoubleUtil.LessThanOrClose(viewPortBounds.Top, elementBounds.Top)
                        && DoubleUtil.LessThanOrClose(elementBounds.Bottom, viewPortBounds.Bottom)) 
                    {
                        return true;
                    }
                } 
                else if (axis == FocusNavigationDirection.Right || axis == FocusNavigationDirection.Left)
                { 
                    if (DoubleUtil.LessThanOrClose(viewPortBounds.Left, elementBounds.Left) 
                        && DoubleUtil.LessThanOrClose(elementBounds.Right, viewPortBounds.Right))
                    { 
                        return true;
                    }
                }
            } 

 
            return false; 
        }
 
        private static void OnGotFocus(object sender, KeyboardFocusChangedEventArgs e)
        {
            ItemsControl itemsControl = (ItemsControl)sender;
            UIElement itemContainer = e.OriginalSource as UIElement; 
            if ((itemContainer != null) && (itemContainer != itemsControl))
            { 
                object item = itemsControl.ItemContainerGenerator.ItemFromContainer(itemContainer); 
                if (item != DependencyProperty.UnsetValue)
                    itemsControl._focusedItem = item; 
            }
        }

 
        /// 
        /// The item corresponding to the UI container which has focus. 
        /// Virtualizing panels remove visual children you can't see. 
        /// When you scroll the focused element out of view we throw
        /// focus back on to the items control and remember the item which 
        /// was focused.  When it scrolls back into view (and focus is
        /// still on the ItemsControl) we'll focus it.
        /// 
        internal object FocusedItem 
        {
            get { return _focusedItem; } 
        } 

        private object _focusedItem; 

        internal class ItemNavigateArgs
        {
            public ItemNavigateArgs(InputDevice deviceUsed, ModifierKeys modifierKeys) 
            {
                _deviceUsed = deviceUsed; 
                _modifierKeys = modifierKeys; 
            }
 
            public InputDevice DeviceUsed { get { return _deviceUsed; } }

            private InputDevice _deviceUsed;
            private ModifierKeys _modifierKeys; 

            public static ItemNavigateArgs Empty 
            { 
                get
                { 
                    if (_empty == null)
                    {
                        _empty = new ItemNavigateArgs(null, ModifierKeys.None);;
                    } 
                    return _empty;
                } 
            } 
            private static ItemNavigateArgs _empty;
        } 

        //
        internal virtual void FocusItem(object item, ItemNavigateArgs itemNavigateArgs)
        { 
            if (item != null)
            { 
                UIElement container = ItemContainerGenerator.ContainerFromItem(item) as UIElement; 
                if (container != null)
                { 
                    Keyboard.Focus(container);
                }
            }
            if (itemNavigateArgs.DeviceUsed is KeyboardDevice) 
            {
                KeyboardNavigation.ShowFocusVisual(); 
            } 
        }
 
        // ISSUE: IsLogicalVertical and IsLogicalHorizontal are rough guesses as to whether
        //        the ItemsHost is virtualizing in a particular direction.  Ideally this
        //        would be exposed through the IScrollInfo.
 

        internal bool IsLogicalVertical 
        { 
            get
            { 
                return (ItemsHost != null && ItemsHost.HasLogicalOrientation && ItemsHost.LogicalOrientation == Orientation.Vertical &&
                        ScrollHost != null && ScrollHost.CanContentScroll);
            }
        } 

        internal bool IsLogicalHorizontal 
        { 
            get
            { 
                return (ItemsHost != null && ItemsHost.HasLogicalOrientation && ItemsHost.LogicalOrientation == Orientation.Horizontal &&
                        ScrollHost != null && ScrollHost.CanContentScroll);
            }
        } 

        internal ScrollViewer ScrollHost 
        { 
            get
            { 
                if (!ReadControlFlag(ControlBoolFlags.ScrollHostValid))
                {
                    if (_itemsHost == null)
                    { 
                        return null;
                    } 
                    else 
                    {
                        // We have an itemshost, so walk up the tree looking for the ScrollViewer 
                        for (DependencyObject current = _itemsHost; current != this && current != null; current = VisualTreeHelper.GetParent(current))
                        {
                            ScrollViewer scrollViewer = current as ScrollViewer;
                            if (scrollViewer != null) 
                            {
                                _scrollHost = scrollViewer; 
                                break; 
                            }
                        } 

                        WriteControlFlag(ControlBoolFlags.ScrollHostValid, true);
                    }
                } 

                return _scrollHost; 
            } 
        }
 
        internal static TimeSpan AutoScrollTimeout
        {
            get
            { 
                // NOTE: NtUser does the following (file: windows/ntuser/kernel/sysmet.c)
                //     gpsi->dtLBSearch = dtTime * 4;            // dtLBSearch   =  4  * gdtDblClk 
                //     gpsi->dtScroll = gpsi->dtLBSearch / 5;  // dtScroll     = 4/5 * gdtDblClk 

                return TimeSpan.FromMilliseconds(MS.Win32.SafeNativeMethods.GetDoubleClickTime() * 0.8); 
            }
        }

        internal void DoAutoScroll() 
        {
            DoAutoScroll(FocusedItem); 
        } 

        internal void DoAutoScroll(object startingItem) 
        {
            // Attempt to compute positions based on the ScrollHost.
            // If that doesn't exist, use the ItemsHost.
            FrameworkElement relativeTo = ScrollHost != null ? (FrameworkElement)ScrollHost : ItemsHost; 
            if (relativeTo != null)
            { 
                // Figure out where the mouse is w.r.t. the ItemsControl. 

                Point mousePosition = Mouse.GetPosition(relativeTo); 

                // Take the bounding box of the ListBox and scroll against that
                Rect bounds = new Rect(new Point(), relativeTo.RenderSize);
                bool focusChanged = false; 

                if (mousePosition.Y < bounds.Top) 
                { 
                    NavigateByLine(startingItem, FocusNavigationDirection.Up, new ItemNavigateArgs(Mouse.PrimaryDevice, Keyboard.Modifiers));
                    focusChanged = startingItem != FocusedItem; 
                }
                else if (mousePosition.Y >= bounds.Bottom)
                {
                    NavigateByLine(startingItem, FocusNavigationDirection.Down, new ItemNavigateArgs(Mouse.PrimaryDevice, Keyboard.Modifiers)); 
                    focusChanged = startingItem != FocusedItem;
                } 
 
                // Try horizontal scroll if vertical scroll did not happen
                if (!focusChanged) 
                {
                    if (mousePosition.X < bounds.Left)
                    {
                        FocusNavigationDirection direction = FocusNavigationDirection.Left; 
                        if (IsRTL(relativeTo))
                        { 
                            direction = FocusNavigationDirection.Right; 
                        }
 
                        NavigateByLine(startingItem, direction, new ItemNavigateArgs(Mouse.PrimaryDevice, Keyboard.Modifiers));
                    }
                    else if (mousePosition.X >= bounds.Right)
                    { 
                        FocusNavigationDirection direction = FocusNavigationDirection.Right;
                        if (IsRTL(relativeTo)) 
                        { 
                            direction = FocusNavigationDirection.Left;
                        } 

                        NavigateByLine(startingItem, direction, new ItemNavigateArgs(Mouse.PrimaryDevice, Keyboard.Modifiers));
                    }
                } 
            }
        } 
 
        private bool IsRTL(FrameworkElement element)
        { 
            FlowDirection flowDirection = element.FlowDirection;
            return (flowDirection == FlowDirection.RightToLeft);
        }
 
        private object GetEncapsulatingItem(FrameworkElement element)
        { 
            object item = DependencyProperty.UnsetValue; 

            while (item == DependencyProperty.UnsetValue && element != null) 
            {
                item = ItemContainerGenerator.ItemFromContainer(element);
                element = VisualTreeHelper.GetParent(element) as FrameworkElement;
            } 

            return item; 
        } 

        #endregion Keyboard Navigation 

        #endregion

        //------------------------------------------------------ 
        //
        //  Private Methods 
        // 
        //------------------------------------------------------
 
        #region Private Methods

        private void ApplyItemContainerStyle(DependencyObject container, object item)
        { 
            FrameworkObject foContainer = new FrameworkObject(container);
 
            // don't overwrite a locally-defined style (bug 1018408) 
            if (!foContainer.IsStyleSetFromGenerator &&
                container.ReadLocalValue(FrameworkElement.StyleProperty) != DependencyProperty.UnsetValue) 
            {
                return;
            }
 
            // Control's ItemContainerStyle has first stab
            Style style = ItemContainerStyle; 
 
            // no ItemContainerStyle set, try ItemContainerStyleSelector
            if (style == null) 
            {
                if (ItemContainerStyleSelector != null)
                {
                    style = ItemContainerStyleSelector.SelectStyle(item, container); 
                }
            } 
 
            // apply the style, if found
            if (style != null) 
            {
                // verify style is appropriate before applying it
                if (!style.TargetType.IsInstanceOfType(container))
                    throw new InvalidOperationException(SR.Get(SRID.StyleForWrongType, style.TargetType.Name, container.GetType().Name)); 

                foContainer.Style = style; 
                foContainer.IsStyleSetFromGenerator = true; 
            }
            else if (foContainer.IsStyleSetFromGenerator) 
            {
                // if Style was formerly set from ItemContainerStyle, clear it
                foContainer.IsStyleSetFromGenerator = false;
                container.ClearValue(FrameworkElement.StyleProperty); 
            }
        } 
 
        private void RemoveItemContainerStyle(DependencyObject container)
        { 
            FrameworkObject foContainer = new FrameworkObject(container);

            if (foContainer.IsStyleSetFromGenerator)
            { 
                container.ClearValue(FrameworkElement.StyleProperty);
            } 
        } 

 
        internal object GetItemOrContainerFromContainer(DependencyObject container)
        {
            object item = ItemContainerGenerator.ItemFromContainer(container);
 
            if (item == DependencyProperty.UnsetValue
                && ItemsControlFromItemContainer(container) == this 
                && ((IGeneratorHost)this).IsItemItsOwnContainer(container)) 
            {
                item = container; 
            }

            return item;
        } 

        #endregion 
 
        #region ItemValueStorage
 

        internal object ReadItemValue(object item, int dpIndex)
        {
            if (item != null) 
            {
                List> itemValues = GetItemValues(item); 
 
                if (itemValues != null)
                { 
                    for (int i = 0; i < itemValues.Count; i++)
                    {
                        if (itemValues[i].Key == dpIndex)
                        { 
                            return itemValues[i].Value;
                        } 
                    } 
                }
            } 

            return null;
        }
 
        /// 
        /// Stores the given value in ItemValueStorage, associating it with the given item and DependencyProperty index. 
        ///  
        /// 
        ///  
        /// global index of a DependencyProperty
        internal void StoreItemValue(object item, object value, int dpIndex)
        {
            if (item != null) 
            {
                List> itemValues = EnsureItemValues(item); 
 
                //
                // Find the key, if it exists, and modify its value.  Since the number of DPs we want to store 
                // is typically very small, using a List in this manner is faster than hashing
                //

                bool found = false; 
                KeyValuePair keyValue = new KeyValuePair(dpIndex, value);
 
                for (int j = 0; j < itemValues.Count; j++) 
                {
                    if (itemValues[j].Key == dpIndex) 
                    {
                        itemValues[j] = keyValue;
                        found = true;
                        break; 
                    }
                } 
 
                if (!found)
                { 
                    itemValues.Add(keyValue);
                }
            }
        } 

 
        ///  
        /// Returns the ItemValues list for a given item.  May return null if one hasn't been set yet.
        ///  
        /// 
        /// 
        private List> GetItemValues(object item)
        { 
            return GetItemValues(item, ItemValueStorageField.GetValue(this));
        } 
 
        private List> GetItemValues(object item,
                                                              Dictionary, List>> itemValueStorage) 
        {
            Debug.Assert(item != null);
            List> itemValues = null;
            WeakReferenceKey key; 

            if (itemValueStorage != null) 
            { 
                key = new WeakReferenceKey(item);
                itemValueStorage.TryGetValue(key, out itemValues); 
            }

            return itemValues;
        } 

 
        private List> EnsureItemValues(object item) 
        {
            WeakReferenceKey key; 

            Dictionary, List>> itemValueStorage = EnsureItemValueStorage();
            List> itemValues = GetItemValues(item, itemValueStorage);
 
            if (itemValues == null && HashHelper.HasReliableHashCode(item))
            { 
                key = new WeakReferenceKey(item); 
                itemValues = new List>(3);    // So far the only use of this is to store three values.
                itemValueStorage[key] = itemValues; 
            }

            return itemValues;
        } 

 
        private Dictionary, List>> EnsureItemValueStorage() 
        {
            Dictionary, List>> itemValueStorage = ItemValueStorageField.GetValue(this); 

            if (itemValueStorage == null)
            {
                itemValueStorage = new Dictionary, List>>(Items.Count); 
                ItemValueStorageField.SetValue(this, itemValueStorage);
            } 
 
            return itemValueStorage;
        } 

        /// 
        /// Sets all values saved in ItemValueStorage for the given item onto the container
        ///  
        /// 
        ///  
        private void SetItemValuesOnContainer(DependencyObject container, object item, int[] dpIndices) 
        {
            List> itemValues = GetItemValues(item); 

            if (itemValues != null)
            {
                for (int i = 0; i < itemValues.Count; i++) 
                {
                    int dpIndex = itemValues[i].Key; 
 
                    for (int j = 0; j < dpIndices.Length; j++)
                    { 
                        if (dpIndex == dpIndices[j])
                        {
                            object value = itemValues[i].Value;
                            EntryIndex entryIndex = container.LookupEntry(dpIndex); 
                            ModifiedItemValue modifiedItemValue = value as ModifiedItemValue;
                            DependencyProperty dp = DependencyProperty.RegisteredPropertyList.List[dpIndex]; 
 
                            if (modifiedItemValue == null)
                            { 
                                // set as local value
                                if (dp != null)
                                {
                                    // for real properties, call SetValue so that the property's 
                                    // change-callback is called
                                    container.SetValue(dp, value); 
                                } 
                                else
                                { 
                                    // for "fake" properties (no corresponding DP - e.g. VSP's desired-size),
                                    // set the property directly into the effective value table
                                    container.SetEffectiveValue(entryIndex, null /*dp*/, dpIndex, null /*metadata*/, value, BaseValueSourceInternal.Local);
                                } 
                            }
                            else if (modifiedItemValue.IsCoercedWithCurrentValue) 
                            { 
                                // set as current-value
                                container.SetCurrentValue(dp, modifiedItemValue.Value); 
                            }
                            break;
                        }
                    } 
                }
            } 
        } 

        ///  
        /// Stores the value of a container for the given item and set of dependency properties
        /// 
        /// 
        ///  
        /// 
        private void StoreItemValues(DependencyObject container, object item, int[] dpIndices) 
        { 

            // 
            // Loop through all DPs we care about storing.  If the container has a current-value or locally-set value we'll store it.
            //
            for (int i = 0; i < dpIndices.Length; i++)
            { 
                int dpIndex = dpIndices[i];
                EntryIndex entryIndex = container.LookupEntry(dpIndex); 
 
                if (entryIndex.Found)
                { 
                    EffectiveValueEntry entry = container.EffectiveValues[entryIndex.Index];

                    if (entry.BaseValueSourceInternal == BaseValueSourceInternal.Local && !entry.HasModifiers)
                    { 
                        // store local values that aren't modified
                        StoreItemValue(item, entry.Value, dpIndex); 
                    } 
                    else if (entry.IsCoercedWithCurrentValue)
                    { 
                        // store current-values
                        StoreItemValue(item,
                                        new ModifiedItemValue(entry.ModifiedValue.CoercedValue, FullValueSource.IsCoercedWithCurrentValue),
                                        dpIndex); 
                    }
                } 
 
            }
        } 

        // This class reprents an item value that arises from a non-local source (e.g. current-value)
        private class ModifiedItemValue
        { 
            public ModifiedItemValue(object value, FullValueSource valueSource)
            { 
                _value = value; 
                _valueSource = valueSource;
            } 

            public object Value { get { return _value; } }

            public bool IsCoercedWithCurrentValue 
            {
                get { return (_valueSource & FullValueSource.IsCoercedWithCurrentValue) != 0; } 
            } 

            object _value; 
            FullValueSource _valueSource;
        }

 
        #endregion
 
        #region Method Overrides 

        ///  
        ///     Returns a string representation of this object.
        /// 
        /// 
        public override string ToString() 
        {
            // HasItems may be wrong when underlying collection does not notify, 
            // but this function should try to return what's consistent with ItemsControl state. 
            int itemsCount = HasItems ? Items.Count : 0;
            return SR.Get(SRID.ToStringFormatString_ItemsControl, this.GetType(), itemsCount); 
        }

        #endregion
 
        #region Data
 
        private ItemCollection _items;                      // Cache for Items property 
        private ItemContainerGenerator _itemContainerGenerator;
        private Panel _itemsHost; 
        private ScrollViewer _scrollHost;
        private ObservableCollection _groupStyle = new ObservableCollection();

 
        // ItemValueStorage.  For each data item it stores a list of (DP, value) pairs that we want to preserve on the container.
        private static readonly UncommonField, List>>> ItemValueStorageField = 
                            new UncommonField, List>>>(); 

        // Since ItemValueStorage is private and only used for TreeView virtualization we hardcode the DPs that we'll store in it. 
        // If we make this available as a service to the rest of the platform we'd come up with some sort of DP registration mechanism.
        private static readonly int[] ItemValueStorageIndices = new int[] { ItemValueStorageField.GlobalIndex, TreeViewItem.IsExpandedProperty.GlobalIndex };

 
        #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