TreeViewItem.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ Dotnetfx_Vista_SP2 / Dotnetfx_Vista_SP2 / 8.0.50727.4016 / DEVDIV / depot / DevDiv / releases / Orcas / QFE / wpf / src / Framework / System / Windows / Controls / TreeViewItem.cs / 1 / TreeViewItem.cs

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

using System; 
using System.Collections; 
using System.Collections.Specialized;
using System.ComponentModel; 
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls.Primitives; 
using System.Windows.Input;
using System.Windows.Media; 
using MS.Internal; 
using MS.Internal.KnownBoxes;
 
namespace System.Windows.Controls
{
    /// 
    ///     A child of a . 
    /// 
    [TemplatePart(Name = "PART_Header", Type = typeof(FrameworkElement))] 
    [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(TreeViewItem))] 
    public class TreeViewItem : HeaderedItemsControl, VirtualizingStackPanel.IProvideStackingSize
    { 
        #region Constructors

        static TreeViewItem()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(typeof(TreeViewItem)));
            VirtualizingStackPanel.IsVirtualizingProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(TreeViewItem)); 

            KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(KeyboardNavigationMode.Continue)); 
            KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(KeyboardNavigationMode.None));
            IsTabStopProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

            EventManager.RegisterClassHandler(typeof(TreeViewItem), FrameworkElement.RequestBringIntoViewEvent, new RequestBringIntoViewEventHandler(OnRequestBringIntoView)); 
            EventManager.RegisterClassHandler(typeof(TreeViewItem), Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMouseButtonDown), true);
        } 
 
        /// 
        ///     Creates an instance of this control. 
        /// 
        public TreeViewItem()
        {
        } 

        #endregion 
 
        #region Public Properties
 
        /// 
        ///     The DependencyProperty for the  property.
        ///     Default Value: false
        ///  
        public static readonly DependencyProperty IsExpandedProperty =
            DependencyProperty.Register( 
                    "IsExpanded", 
                    typeof(bool),
                    typeof(TreeViewItem), 
                    new FrameworkPropertyMetadata(
                            BooleanBoxes.FalseBox,
                            new PropertyChangedCallback(OnIsExpandedChanged)));
 
        /// 
        ///     Specifies whether this item has expanded its children or not. 
        ///  
        public bool IsExpanded
        { 
            get { return (bool) GetValue(IsExpandedProperty); }
            set { SetValue(IsExpandedProperty, value); }
        }
 
        private bool CanExpand
        { 
            get { return HasItems; } 
        }
 
        private static void OnIsExpandedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TreeViewItem item = (TreeViewItem) d;
            bool isExpanded = (bool) e.NewValue; 

            if (!isExpanded) 
            { 
                TreeView tv = item.ParentTreeView;
                if (tv != null) 
                {
                    tv.HandleSelectionAndCollapsed(item);
                }
            } 

            TreeViewItemAutomationPeer peer = UIElementAutomationPeer.FromElement(item) as TreeViewItemAutomationPeer; 
            if (peer != null) 
            {
                peer.RaiseExpandCollapseAutomationEvent((bool)e.OldValue, isExpanded); 
            }

            if (isExpanded)
            { 
                item.OnExpanded(new RoutedEventArgs(ExpandedEvent, item));
            } 
            else 
            {
                item.OnCollapsed(new RoutedEventArgs(CollapsedEvent, item)); 
            }
        }

        ///  
        ///     The DependencyProperty for the  property.
        ///     Default Value: false 
        ///  
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register( 
                    "IsSelected",
                    typeof(bool),
                    typeof(TreeViewItem),
                    new FrameworkPropertyMetadata( 
                            BooleanBoxes.FalseBox,
                            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
                            new PropertyChangedCallback(OnIsSelectedChanged))); 

        ///  
        ///     Specifies whether this item is selected or not.
        /// 
        public bool IsSelected
        { 
            get { return (bool) GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); } 
        } 

        private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            TreeViewItem item = (TreeViewItem)d;
            bool isSelected = (bool) e.NewValue;
 
            item.Select(isSelected);
 
            TreeViewItemAutomationPeer peer = UIElementAutomationPeer.FromElement(item) as TreeViewItemAutomationPeer; 
            if (peer != null)
            { 
                peer.RaiseAutomationIsSelectedChanged(isSelected);
            }

            if (isSelected) 
            {
                item.OnSelected(new RoutedEventArgs(SelectedEvent, item)); 
            } 
            else
            { 
                item.OnUnselected(new RoutedEventArgs(UnselectedEvent, item));
            }
        }
 
        /// 
        ///     DependencyProperty for . 
        ///  
        public static readonly DependencyProperty IsSelectionActiveProperty = Selector.IsSelectionActiveProperty.AddOwner(typeof(TreeViewItem));
 
        /// 
        ///     Indicates whether the keyboard focus is within the TreeView.
        ///     When keyboard focus moves to a Menu or Toolbar, then the selection remains active.
        ///     Use this property to style the TreeViewItem to look different when focus is not within the TreeView. 
        /// 
        [Browsable(false), Category("Appearance"), ReadOnly(true)] 
        public bool IsSelectionActive 
        {
            get 
            {
                return (bool)GetValue(IsSelectionActiveProperty);
            }
        } 

        #endregion 
 
        #region Public Events
 
        /// 
        ///     Event fired when  becomes true.
        /// 
        public static readonly RoutedEvent ExpandedEvent = EventManager.RegisterRoutedEvent("Expanded", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItem)); 

        ///  
        ///     Event fired when  becomes true. 
        /// 
        [Category("Behavior")] 
        public event RoutedEventHandler Expanded
        {
            add
            { 
                AddHandler(ExpandedEvent, value);
            } 
 
            remove
            { 
                RemoveHandler(ExpandedEvent, value);
            }
        }
 
        /// 
        ///     Called when  becomes true. 
        ///     Default implementation fires the  event. 
        /// 
        /// Event arguments. 
        protected virtual void OnExpanded(RoutedEventArgs e)
        {
            RaiseEvent(e);
        } 

        ///  
        ///     Event fired when  becomes false. 
        /// 
        public static readonly RoutedEvent CollapsedEvent = EventManager.RegisterRoutedEvent("Collapsed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItem)); 

        /// 
        ///     Event fired when  becomes false.
        ///  
        [Category("Behavior")]
        public event RoutedEventHandler Collapsed 
        { 
            add
            { 
                AddHandler(CollapsedEvent, value);
            }

            remove 
            {
                RemoveHandler(CollapsedEvent, value); 
            } 
        }
 
        /// 
        ///     Called when  becomes false.
        ///     Default implementation fires the  event.
        ///  
        /// Event arguments.
        protected virtual void OnCollapsed(RoutedEventArgs e) 
        { 
            RaiseEvent(e);
        } 

        /// 
        ///     Event fired when  becomes true.
        ///  
        public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItem));
 
        ///  
        ///     Event fired when  becomes true.
        ///  
        [Category("Behavior")]
        public event RoutedEventHandler Selected
        {
            add 
            {
                AddHandler(SelectedEvent, value); 
            } 

            remove 
            {
                RemoveHandler(SelectedEvent, value);
            }
        } 

        ///  
        ///     Called when  becomes true. 
        ///     Default implementation fires the  event.
        ///  
        /// Event arguments.
        protected virtual void OnSelected(RoutedEventArgs e)
        {
            RaiseEvent(e); 
        }
 
        ///  
        ///     Event fired when  becomes false.
        ///  
        public static readonly RoutedEvent UnselectedEvent = EventManager.RegisterRoutedEvent("Unselected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItem));

        /// 
        ///     Event fired when  becomes false. 
        /// 
        [Category("Behavior")] 
        public event RoutedEventHandler Unselected 
        {
            add 
            {
                AddHandler(UnselectedEvent, value);
            }
 
            remove
            { 
                RemoveHandler(UnselectedEvent, value); 
            }
        } 

        /// 
        ///     Called when  becomes false.
        ///     Default implementation fires the  event. 
        /// 
        /// Event arguments. 
        protected virtual void OnUnselected(RoutedEventArgs e) 
        {
            RaiseEvent(e); 
        }

        #endregion
 
        #region Internal Methods
 
        ///  
        /// TreeView keeps track of the size estimate; forward the call to it.
        ///  
        /// 
        double VirtualizingStackPanel.IProvideStackingSize.EstimatedContainerSize(bool isHorizontal)
        {
            TreeView parent = ParentTreeView; 
            Size estimate = Size.Empty;
 
            if (parent != null) 
            {
                estimate = ParentTreeView.CurrentContainerSizeEstimate; 
            }

            return isHorizontal ? estimate.Width : estimate.Height;
        } 

        ///  
        /// Return the size of the header in the requested direction. 
        /// 
        ///  
        /// 
        double VirtualizingStackPanel.IProvideStackingSize.HeaderSize(bool isHorizontal)
        {
            UIElement header = null; 
            ControlTemplate template = Template;
 
            if (template != null) 
            {
                header = template.FindName("PART_Header", this) as UIElement; 

                if (header != null)
                {
                    return isHorizontal ? header.DesiredSize.Width : header.DesiredSize.Height; 
                }
            } 
 
            return 0d;
        } 

        #endregion

        #region Implementation 

        #region Tree 
 
        /// 
        ///     Walks up the parent chain of TreeViewItems to the top TreeView. 
        /// 
        internal TreeView ParentTreeView
        {
            get 
            {
                ItemsControl parent = ParentItemsControl; 
                while (parent != null) 
                {
                    TreeView tv = parent as TreeView; 
                    if (tv != null)
                    {
                        return tv;
                    } 

                    parent = ItemsControl.ItemsControlFromItemContainer(parent); 
                } 

                return null; 
            }
        }

        ///  
        ///     Returns the immediate parent TreeViewItem. Null if the parent is a TreeView.
        ///  
        internal TreeViewItem ParentTreeViewItem 
        {
            get 
            {
                return ParentItemsControl as TreeViewItem;
            }
        } 

        ///  
        ///     Returns the immediate parent ItemsControl. 
        /// 
        internal ItemsControl ParentItemsControl 
        {
            get
            {
                return ItemsControl.ItemsControlFromItemContainer(this); 
            }
        } 
 
        #endregion
 
        #region Selection

        /// 
        /// Called when the visual parent of this element changes. 
        /// 
        ///  
        protected internal override void OnVisualParentChanged(DependencyObject oldParent) 
        {
            // When TreeViewItem is added to the visual tree we check if IsSelected is set to true 
            // In this case we need to update the tree selection
            if (VisualTreeHelper.GetParent(this) != null)
            {
                if (IsSelected) 
                {
                    Select(true); 
                } 
            }
 
            base.OnVisualParentChanged(oldParent);
        }

        private void Select(bool selected) 
        {
            TreeView tree = ParentTreeView; 
            ItemsControl parent = ParentItemsControl; 
            if ((tree != null) && (parent != null) && !tree.IsSelectionChangeActive)
            { 
                // Give the TreeView a reference to this container and its data
                object data = parent.GetItemOrContainerFromContainer(this);
                tree.ChangeSelection(data, this, selected);
            } 
        }
 
        private bool ContainsSelection 
        {
            get { return ReadControlFlag(ControlBoolFlags.ContainsSelection); } 
            set { WriteControlFlag(ControlBoolFlags.ContainsSelection, value); }
        }

        internal void UpdateContainsSelection(bool selected) 
        {
            TreeViewItem parent = ParentTreeViewItem; 
            while (parent != null) 
            {
                parent.ContainsSelection = selected; 
                parent = parent.ParentTreeViewItem;
            }
        }
 
        #endregion
 
        #region Input 

        ///  
        ///     This method is invoked when the IsFocused property changes to true.
        /// 
        /// Event arguments.
        protected override void OnGotFocus(RoutedEventArgs e) 
        {
            Select(true); 
            base.OnGotFocus(e); 
        }
 
        /// 
        ///     Called when the left mouse button is pressed down.
        /// 
        /// Event arguments 
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        { 
            if (!e.Handled && IsEnabled) 
            {
                if (Focus()) 
                {
                    e.Handled = true;
                }
 
                if ((e.ClickCount % 2) == 0)
                { 
                    IsExpanded = !IsExpanded; 
                    e.Handled = true;
                } 
            }
            base.OnMouseLeftButtonDown(e);
        }
 
        /// 
        ///     Called when a keyboard key is pressed down. 
        ///  
        /// Event Arguments
        protected override void OnKeyDown(KeyEventArgs e) 
        {
            base.OnKeyDown(e);
            if (!e.Handled)
            { 
                switch (e.Key)
                { 
                    case Key.Add: 
                        if (CanExpandOnInput && !IsExpanded)
                        { 
                            IsExpanded = true;
                            e.Handled = true;
                        }
                        break; 

                    case Key.Subtract: 
                        if (CanExpandOnInput && IsExpanded) 
                        {
                            IsExpanded = false; 
                            e.Handled = true;
                        }
                        break;
 
                    case Key.Left:
                    case Key.Right: 
                        if (LogicalLeft(e.Key)) 
                        {
                            if (!IsControlKeyDown && CanExpandOnInput && IsExpanded) 
                            {
                                if (IsFocused)
                                {
                                    IsExpanded = false; 
                                }
                                else 
                                { 
                                    Focus();
                                } 
                                e.Handled = true;
                            }
                        }
                        else 
                        {
                            if (!IsControlKeyDown && CanExpandOnInput) 
                            { 
                                if (!IsExpanded)
                                { 
                                    IsExpanded = true;
                                    e.Handled = true;
                                }
                                else if (HandleDownKey()) 
                                {
                                    e.Handled = true; 
                                } 
                            }
                        } 
                        break;

                    case Key.Down:
                        if (!IsControlKeyDown && HandleDownKey()) 
                        {
                            e.Handled = true; 
                        } 
                        break;
 
                    case Key.Up:
                        if (!IsControlKeyDown && HandleUpKey())
                        {
                            e.Handled = true; 
                        }
                        break; 
                } 
            }
        } 

        private bool LogicalLeft(Key key)
        {
            bool invert = (FlowDirection == FlowDirection.RightToLeft); 
            return (!invert && (key == Key.Left)) || (invert && (key == Key.Right));
        } 
 
        private static bool IsControlKeyDown
        { 
            get
            {
                return ((Keyboard.Modifiers & ModifierKeys.Control) == (ModifierKeys.Control));
            } 
        }
 
        private bool CanExpandOnInput 
        {
            get 
            {
                return CanExpand && IsEnabled;
            }
        } 

        internal bool HandleUpKey() 
        { 
            if (AllowHandleKeyEvent(FocusNavigationDirection.Up))
            { 
                ItemsControl item = FindPreviousFocusableItem();

                if (item != null)
                { 
                    if (item == ParentItemsControl && item == ParentTreeView)
                    { 
                        return true; // Prevents KeyboardNavigation from focusing one of our children 
                    }
 
                    return item.Focus();
                }
            }
 
            return false; // Not handled
        } 
 
        internal bool HandleDownKey()
        { 
            if (AllowHandleKeyEvent(FocusNavigationDirection.Down))
            {
                return FocusDown();
            } 

            return false; // Not handled 
        } 

        private bool AllowHandleKeyEvent(FocusNavigationDirection direction) 
        {
            if (!IsSelected)
            {
                return false; 
            }
 
            DependencyObject currentFocus = Keyboard.FocusedElement as DependencyObject; 
            if (currentFocus != null && UIElementHelper.IsUIElementOrUIElement3D(currentFocus))
            { 
                DependencyObject predict = UIElementHelper.PredictFocus(currentFocus, direction);
                if (predict != currentFocus)
                {
                    while (predict != null) 
                    {
                        TreeViewItem item = predict as TreeViewItem; 
                        if (item == this) 
                        {
                            return false; // There is a focusable item in the header 
                        }
                        else if ((item != null) || (predict is TreeView))
                        {
                            return true; 
                        }
 
                        predict = VisualTreeHelper.GetParent(predict); 
                    }
                } 
            }

            return true;
        } 

        internal static bool FocusIntoItem(TreeViewItem item) 
        { 
            Debug.Assert(item.IsEnabled, "Only call FocusIntoItem with an enabled item");
 
            TreeViewItem lastItem = FindLastFocusableItem(item);

            if (lastItem != null)
            { 
                return lastItem.Focus();
            } 
 
            return false;
        } 

        internal bool FocusDown()
        {
            TreeViewItem item = FindNextFocusableItem(true); 

            if (item != null) 
            { 
                return item.Focus();
            } 

            return false;
        }
 

        ///  
        /// Returns the next item in the TreeView hierarchy, regardless of depth. 
        /// 
        ///  
        private TreeViewItem FindNextFocusableItem(bool walkIntoSubtree)
        {
            //
            // First walk into this item's subtree 
            //
 
            if (walkIntoSubtree && IsExpanded && CanExpand) 
            {
                TreeViewItem item = ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem; 
                if (item != null)
                {
                    if (item.IsEnabled)
                    { 
                        return item;
                    } 
                    else 
                    {
                        return item.FindNextFocusableItem(false); 
                    }
                }
            }
 
            //
            // Otherwise go to the next sibling 
            // 

            ItemsControl parent = ParentItemsControl; 
            if (parent != null)
            {
                TreeViewItem item;
                int index = parent.ItemContainerGenerator.IndexFromContainer(this); 
                int count = parent.Items.Count;
                while (index < count) 
                { 
                    // Find the next sibling
                    index++; 
                    item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem;
                    if ((item != null) && item.IsEnabled)
                    {
                        return item; 
                    }
                } 
 
                // This item has no next sibling, find the parent's next sibling
                item = parent as TreeViewItem; 
                if (item != null)
                {
                    return item.FindNextFocusableItem(false);
                } 
            }
 
            return null; // Not handled 
        }
 

        /// 
        /// Returns the previous item in the TreeView hierarchy, regardless of depth.
        ///  
        /// 
        private ItemsControl FindPreviousFocusableItem() 
        { 
            ItemsControl parent = ParentItemsControl;
            if (parent != null) 
            {
                int index = parent.ItemContainerGenerator.IndexFromContainer(this);
                while (index > 0)
                { 
                    index--;
                    TreeViewItem item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; 
                    if ((item != null) && item.IsEnabled) 
                    {
                        TreeViewItem lastItem = FindLastFocusableItem(item); 
                        if (lastItem != null)
                        {
                            return lastItem;
                        } 
                    }
                } 
 
                return parent;
            } 

            return null;
        }
 

        ///  
        /// Returns the last focusable item in the given subtree. 
        /// 
        ///  
        private static TreeViewItem FindLastFocusableItem(TreeViewItem item)
        {
            Debug.Assert(item.IsEnabled, "Only call FocusIntoItem with an enabled item");
 
            TreeViewItem lastItem = null;
 
            // Find the last child in the subtree. 
            int index = -1;
            TreeViewItem parent = null; 
            while (item != null)
            {
                if (item.IsEnabled)
                { 
                    if (!item.IsExpanded || !item.CanExpand)
                    { 
                        return item; 
                    }
 
                    lastItem = item;
                    parent = item;
                    index = item.Items.Count - 1;
                } 
                else if (index > 0)
                { 
                    index--; 
                }
                else 
                {
                    break;
                }
 
                item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem;
            } 
 
            if (lastItem != null)
            { 
                return lastItem;
            }

            return null; 
        }
 
        ///  
        /// This should be PredictFocus but since UIElement.PredictFocus is sealed by FE we can't override it.
        /// TreeViewItem has its own code for deciding where focus should go. 
        /// 
        /// 
        /// 
        internal DependencyObject InternalPredictFocus(FocusNavigationDirection direction) 
        {
            switch (direction) 
            { 
                case FocusNavigationDirection.Left:
                case FocusNavigationDirection.Up: 
                    return FindPreviousFocusableItem();
                case FocusNavigationDirection.Right:
                case FocusNavigationDirection.Down:
                    return FindNextFocusableItem(true); 
                default:
                    return null; 
            } 

        } 


        private static void OnMouseButtonDown(object sender, MouseButtonEventArgs e)
        { 
            TreeViewItem tvi = (TreeViewItem)sender;
            TreeView tv = tvi.ParentTreeView; 
            if (tv != null) 
            {
                tv.HandleMouseButtonDown(); 
            }
        }
        private static void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
        { 
            if (e.TargetObject == sender)
            { 
                ((TreeViewItem)sender).HandleBringIntoView(e); 
            }
        } 

        private void HandleBringIntoView(RequestBringIntoViewEventArgs e)
        {
            TreeViewItem parent = ParentTreeViewItem; 
            while (parent != null)
            { 
                if (!parent.IsExpanded) 
                {
                    parent.IsExpanded = true; 
                }

                parent = parent.ParentTreeViewItem;
            } 

            // See FrameworkElement.BringIntoView() comments 
            //dmitryt, bug 1126518. On new/updated elements RenderSize isn't yet computed 
            //so we need to postpone the rect computation until layout is done.
            //this is accomplished by passing Empty rect here and then asking for RenderSize 
            //in IScrollInfo when it actually executes an async MakeVisible command.
            if (e.TargetRect.IsEmpty)
            {
                FrameworkElement header = HeaderElement; 
                if (header != null)
                { 
                    e.Handled = true; 
                    header.BringIntoView();
                } 
            }
        }

        private FrameworkElement HeaderElement 
        {
            get 
            { 
                return GetTemplateChild(HeaderPartName) as FrameworkElement;
            } 
        }

        internal bool HandleScrollByPage(bool up, ScrollViewer scroller, double viewportHeight, double startTop, double startBottom, out double currentDelta)
        { 
            double closeEdge;
            currentDelta = CalculateDelta(up, this, scroller, startTop, startBottom, out closeEdge); 
            if (DoubleUtil.GreaterThan(closeEdge, viewportHeight)) 
            {
                // The item does not fit in view at all 
                return false; // Did not focus
            }
            else if (DoubleUtil.LessThanOrClose(currentDelta, viewportHeight))
            { 
                // This item and all its children fit in view.
                // There may be others that also fit in view, so don't focus now 
                return false; // Did not focus 
            }
            else 
            {
                // This item is partially in view

                // Test if the header element is in view 
                bool headerInView = false;
                FrameworkElement header = HeaderElement; 
                if (header != null) 
                {
                    double delta = CalculateDelta(up, header, scroller, startTop, startBottom); 
                    if (DoubleUtil.LessThanOrClose(delta, viewportHeight))
                    {
                        // The header is in view
                        headerInView = true; 
                    }
                } 
 
                TreeViewItem select = null;
                int count = Items.Count; 
                bool skip = up && ContainsSelection;
                for (int index = (up ? count - 1 : 0); (0 <= index) && (index < count); index = index + (up ? -1 : 1))
                {
                    TreeViewItem item = ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; 
                    if ((item != null) && item.IsEnabled)
                    { 
                        if (skip) 
                        {
                            if (item.IsSelected) 
                            {
                                skip = false;
                                continue; // Go to the next one
                            } 
                            else if (item.ContainsSelection)
                            { 
                                skip = false; 
                                // Look inside this one
                            } 
                            else
                            {
                                continue;
                            } 
                        }
 
                        double delta; 
                        if (item.HandleScrollByPage(up, scroller, viewportHeight, startTop, startBottom, out delta))
                        { 
                            // This item or one of its children was focused
                            return true;
                        }
                        else if (DoubleUtil.GreaterThan(delta, viewportHeight)) 
                        {
                            // This item does not fit 
                            break; 
                        }
                        else 
                        {
                            // This item does fit, but we should continue searching
                            select = item;
                        } 
                    }
                } 
 
                if (select != null)
                { 
                    // Earlier we found an item that fit but didn't focus it at that time
                    if (up)
                    {
                        return select.Focus(); 
                    }
                    else 
                    { 
                        return FocusIntoItem(select);
                    } 
                }
                else if (headerInView)
                {
                    // None of the children could be focused, the header is in view even though 
                    // the whole subtree isn't in view. There shouldn't be any more focusable
                    // items that fit, so select this one. 
                    return Focus(); 
                }
            } 

            return false; // Did not focus
        }
 
        private static double CalculateDelta(bool up, FrameworkElement item, ScrollViewer scroller, double startTop, double startBottom)
        { 
            double closeEdge; 
            return CalculateDelta(up, item, scroller, startTop, startBottom, out closeEdge);
        } 

        private static double CalculateDelta(bool up, FrameworkElement item, ScrollViewer scroller, double startTop, double startBottom, out double closeEdge)
        {
            double top, bottom; 
            GetTopAndBottom(item, scroller, out top, out bottom);
 
            if (up) 
            {
                closeEdge = startBottom - bottom; 
                return startBottom - top;
            }
            else
            { 
                closeEdge = top - startTop;
                return bottom - startTop; 
            } 
        }
 
        internal void GetTopAndBottom(Visual parent, out double top, out double bottom)
        {
            FrameworkElement header = HeaderElement;
            if (header != null) 
            {
                GetTopAndBottom(header, parent, out top, out bottom); 
            } 
            else
            { 
                GetTopAndBottom(this, parent, out top, out bottom);
            }
        }
 
        private static void GetTopAndBottom(FrameworkElement item, Visual parent, out double top, out double bottom)
        { 
            GeneralTransform transform = item.TransformToAncestor(parent); 

            Point upperLeft; 
            if (transform.TryTransform(new Point(0.0, 0.0), out upperLeft))
            {
                top = upperLeft.Y;
            } 
            else
            { 
                top = 0.0; 
            }
 
            Point lowerLeft;
            if (transform.TryTransform(new Point(0.0, item.RenderSize.Height), out lowerLeft))
            {
                bottom = lowerLeft.Y; 
            }
            else 
            { 
                bottom = top + item.RenderSize.Height;
            } 
        }

        #endregion
 
        #region Containers
 
 
        /// 
        ///     Returns true if the item is or should be its own container. 
        /// 
        /// The item to test.
        /// true if its type matches the container type.
        protected override bool IsItemItsOwnContainerOverride(object item) 
        {
            return item is TreeViewItem; 
        } 

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

 
        /// 
        /// We only override this to help with container estimation for virtualization
        /// 
        ///  
        /// 
        protected override Size MeasureOverride(Size constraint) 
        { 
            Size desiredSize = base.MeasureOverride(constraint);
 
            if (IsVirtualizing && !IsExpanded && IsVisible)
            {
                TreeView parent = ParentTreeView;
 
                if (parent != null)
                { 
                    parent.RegisterContainerSize(IsLogicalHorizontal ? desiredSize.Width : desiredSize.Height); 
                }
            } 

            return desiredSize;
        }
 
        /// 
        /// Send down the IsVirtualizing property if it's set on this element. 
        ///  
        /// 
        ///  
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            IsVirtualizingPropagationHelper(this, element); 
        }
 
        // Synchronizes the value of the child's IsVirtualizing property with that of the parent's 
        internal static void IsVirtualizingPropagationHelper(DependencyObject parent, DependencyObject element)
        { 
            SynchronizeValue(VirtualizingStackPanel.IsVirtualizingProperty, parent, element);
            SynchronizeValue(VirtualizingStackPanel.VirtualizationModeProperty, parent, element);

        } 

        private static void SynchronizeValue(DependencyProperty dp, DependencyObject parent, DependencyObject child) 
        { 
            if (IsDefaultValue(dp, parent))
            { 
                child.ClearValue(dp);
            }
            else
            { 
                object value = parent.GetValue(dp);
                child.SetValue(dp, value); 
            } 
        }
 
        private static bool IsDefaultValue(DependencyProperty dp, DependencyObject element)
        {
            bool hasModifiers;
            return element.GetValueSource(dp, null, out hasModifiers) == BaseValueSourceInternal.Default; 
        }
 
        ///  
        ///     This method is invoked when the Items property changes.
        ///  
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            { 
                case NotifyCollectionChangedAction.Remove:
                case NotifyCollectionChangedAction.Reset: 
                    if (ContainsSelection) 
                    {
                        TreeView tree = ParentTreeView; 
                        if ((tree != null) && !tree.IsSelectedContainerHookedUp)
                        {
                            ContainsSelection = false;
                            Select(true); 
                        }
                    } 
                    break; 

                case NotifyCollectionChangedAction.Replace: 
                    if (ContainsSelection)
                    {
                        TreeView tree = ParentTreeView;
                        if (tree != null) 
                        {
                            // When Selected item is replaced - remove the selection 
                            // Revisit the condition when we support duplicate items in Items collection: if e.OldItems[0] is the same as selected items we will unselect the selected item 
                            object selectedItem = tree.SelectedItem;
                            if ((selectedItem != null) && selectedItem.Equals(e.OldItems[0])) 
                            {
                                tree.ChangeSelection(selectedItem, tree.SelectedContainer, false);
                            }
                        } 
                    }
                    break; 
 
                case NotifyCollectionChangedAction.Add:
                case NotifyCollectionChangedAction.Move: 
                    break;

                default:
                    throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, e.Action)); 
            }
        } 
 
        #endregion
 
        #region Automation
        /// 
        /// Creates AutomationPeer ()
        ///  
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new TreeViewItemAutomationPeer(this); 
        }
        #endregion Automation 

        #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 

        #endregion 
 
        #region Data
 
        private const string HeaderPartName = "PART_Header";

        #endregion
    } 
}
 

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

using System; 
using System.Collections; 
using System.Collections.Specialized;
using System.ComponentModel; 
using System.Diagnostics;
using System.Windows;
using System.Windows.Automation.Peers;
using System.Windows.Controls.Primitives; 
using System.Windows.Input;
using System.Windows.Media; 
using MS.Internal; 
using MS.Internal.KnownBoxes;
 
namespace System.Windows.Controls
{
    /// 
    ///     A child of a . 
    /// 
    [TemplatePart(Name = "PART_Header", Type = typeof(FrameworkElement))] 
    [StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(TreeViewItem))] 
    public class TreeViewItem : HeaderedItemsControl, VirtualizingStackPanel.IProvideStackingSize
    { 
        #region Constructors

        static TreeViewItem()
        { 
            DefaultStyleKeyProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(typeof(TreeViewItem)));
            VirtualizingStackPanel.IsVirtualizingProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox)); 
            _dType = DependencyObjectType.FromSystemTypeInternal(typeof(TreeViewItem)); 

            KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(KeyboardNavigationMode.Continue)); 
            KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(KeyboardNavigationMode.None));
            IsTabStopProperty.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));

            EventManager.RegisterClassHandler(typeof(TreeViewItem), FrameworkElement.RequestBringIntoViewEvent, new RequestBringIntoViewEventHandler(OnRequestBringIntoView)); 
            EventManager.RegisterClassHandler(typeof(TreeViewItem), Mouse.MouseDownEvent, new MouseButtonEventHandler(OnMouseButtonDown), true);
        } 
 
        /// 
        ///     Creates an instance of this control. 
        /// 
        public TreeViewItem()
        {
        } 

        #endregion 
 
        #region Public Properties
 
        /// 
        ///     The DependencyProperty for the  property.
        ///     Default Value: false
        ///  
        public static readonly DependencyProperty IsExpandedProperty =
            DependencyProperty.Register( 
                    "IsExpanded", 
                    typeof(bool),
                    typeof(TreeViewItem), 
                    new FrameworkPropertyMetadata(
                            BooleanBoxes.FalseBox,
                            new PropertyChangedCallback(OnIsExpandedChanged)));
 
        /// 
        ///     Specifies whether this item has expanded its children or not. 
        ///  
        public bool IsExpanded
        { 
            get { return (bool) GetValue(IsExpandedProperty); }
            set { SetValue(IsExpandedProperty, value); }
        }
 
        private bool CanExpand
        { 
            get { return HasItems; } 
        }
 
        private static void OnIsExpandedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            TreeViewItem item = (TreeViewItem) d;
            bool isExpanded = (bool) e.NewValue; 

            if (!isExpanded) 
            { 
                TreeView tv = item.ParentTreeView;
                if (tv != null) 
                {
                    tv.HandleSelectionAndCollapsed(item);
                }
            } 

            TreeViewItemAutomationPeer peer = UIElementAutomationPeer.FromElement(item) as TreeViewItemAutomationPeer; 
            if (peer != null) 
            {
                peer.RaiseExpandCollapseAutomationEvent((bool)e.OldValue, isExpanded); 
            }

            if (isExpanded)
            { 
                item.OnExpanded(new RoutedEventArgs(ExpandedEvent, item));
            } 
            else 
            {
                item.OnCollapsed(new RoutedEventArgs(CollapsedEvent, item)); 
            }
        }

        ///  
        ///     The DependencyProperty for the  property.
        ///     Default Value: false 
        ///  
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register( 
                    "IsSelected",
                    typeof(bool),
                    typeof(TreeViewItem),
                    new FrameworkPropertyMetadata( 
                            BooleanBoxes.FalseBox,
                            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault, 
                            new PropertyChangedCallback(OnIsSelectedChanged))); 

        ///  
        ///     Specifies whether this item is selected or not.
        /// 
        public bool IsSelected
        { 
            get { return (bool) GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); } 
        } 

        private static void OnIsSelectedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        {
            TreeViewItem item = (TreeViewItem)d;
            bool isSelected = (bool) e.NewValue;
 
            item.Select(isSelected);
 
            TreeViewItemAutomationPeer peer = UIElementAutomationPeer.FromElement(item) as TreeViewItemAutomationPeer; 
            if (peer != null)
            { 
                peer.RaiseAutomationIsSelectedChanged(isSelected);
            }

            if (isSelected) 
            {
                item.OnSelected(new RoutedEventArgs(SelectedEvent, item)); 
            } 
            else
            { 
                item.OnUnselected(new RoutedEventArgs(UnselectedEvent, item));
            }
        }
 
        /// 
        ///     DependencyProperty for . 
        ///  
        public static readonly DependencyProperty IsSelectionActiveProperty = Selector.IsSelectionActiveProperty.AddOwner(typeof(TreeViewItem));
 
        /// 
        ///     Indicates whether the keyboard focus is within the TreeView.
        ///     When keyboard focus moves to a Menu or Toolbar, then the selection remains active.
        ///     Use this property to style the TreeViewItem to look different when focus is not within the TreeView. 
        /// 
        [Browsable(false), Category("Appearance"), ReadOnly(true)] 
        public bool IsSelectionActive 
        {
            get 
            {
                return (bool)GetValue(IsSelectionActiveProperty);
            }
        } 

        #endregion 
 
        #region Public Events
 
        /// 
        ///     Event fired when  becomes true.
        /// 
        public static readonly RoutedEvent ExpandedEvent = EventManager.RegisterRoutedEvent("Expanded", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItem)); 

        ///  
        ///     Event fired when  becomes true. 
        /// 
        [Category("Behavior")] 
        public event RoutedEventHandler Expanded
        {
            add
            { 
                AddHandler(ExpandedEvent, value);
            } 
 
            remove
            { 
                RemoveHandler(ExpandedEvent, value);
            }
        }
 
        /// 
        ///     Called when  becomes true. 
        ///     Default implementation fires the  event. 
        /// 
        /// Event arguments. 
        protected virtual void OnExpanded(RoutedEventArgs e)
        {
            RaiseEvent(e);
        } 

        ///  
        ///     Event fired when  becomes false. 
        /// 
        public static readonly RoutedEvent CollapsedEvent = EventManager.RegisterRoutedEvent("Collapsed", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItem)); 

        /// 
        ///     Event fired when  becomes false.
        ///  
        [Category("Behavior")]
        public event RoutedEventHandler Collapsed 
        { 
            add
            { 
                AddHandler(CollapsedEvent, value);
            }

            remove 
            {
                RemoveHandler(CollapsedEvent, value); 
            } 
        }
 
        /// 
        ///     Called when  becomes false.
        ///     Default implementation fires the  event.
        ///  
        /// Event arguments.
        protected virtual void OnCollapsed(RoutedEventArgs e) 
        { 
            RaiseEvent(e);
        } 

        /// 
        ///     Event fired when  becomes true.
        ///  
        public static readonly RoutedEvent SelectedEvent = EventManager.RegisterRoutedEvent("Selected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItem));
 
        ///  
        ///     Event fired when  becomes true.
        ///  
        [Category("Behavior")]
        public event RoutedEventHandler Selected
        {
            add 
            {
                AddHandler(SelectedEvent, value); 
            } 

            remove 
            {
                RemoveHandler(SelectedEvent, value);
            }
        } 

        ///  
        ///     Called when  becomes true. 
        ///     Default implementation fires the  event.
        ///  
        /// Event arguments.
        protected virtual void OnSelected(RoutedEventArgs e)
        {
            RaiseEvent(e); 
        }
 
        ///  
        ///     Event fired when  becomes false.
        ///  
        public static readonly RoutedEvent UnselectedEvent = EventManager.RegisterRoutedEvent("Unselected", RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(TreeViewItem));

        /// 
        ///     Event fired when  becomes false. 
        /// 
        [Category("Behavior")] 
        public event RoutedEventHandler Unselected 
        {
            add 
            {
                AddHandler(UnselectedEvent, value);
            }
 
            remove
            { 
                RemoveHandler(UnselectedEvent, value); 
            }
        } 

        /// 
        ///     Called when  becomes false.
        ///     Default implementation fires the  event. 
        /// 
        /// Event arguments. 
        protected virtual void OnUnselected(RoutedEventArgs e) 
        {
            RaiseEvent(e); 
        }

        #endregion
 
        #region Internal Methods
 
        ///  
        /// TreeView keeps track of the size estimate; forward the call to it.
        ///  
        /// 
        double VirtualizingStackPanel.IProvideStackingSize.EstimatedContainerSize(bool isHorizontal)
        {
            TreeView parent = ParentTreeView; 
            Size estimate = Size.Empty;
 
            if (parent != null) 
            {
                estimate = ParentTreeView.CurrentContainerSizeEstimate; 
            }

            return isHorizontal ? estimate.Width : estimate.Height;
        } 

        ///  
        /// Return the size of the header in the requested direction. 
        /// 
        ///  
        /// 
        double VirtualizingStackPanel.IProvideStackingSize.HeaderSize(bool isHorizontal)
        {
            UIElement header = null; 
            ControlTemplate template = Template;
 
            if (template != null) 
            {
                header = template.FindName("PART_Header", this) as UIElement; 

                if (header != null)
                {
                    return isHorizontal ? header.DesiredSize.Width : header.DesiredSize.Height; 
                }
            } 
 
            return 0d;
        } 

        #endregion

        #region Implementation 

        #region Tree 
 
        /// 
        ///     Walks up the parent chain of TreeViewItems to the top TreeView. 
        /// 
        internal TreeView ParentTreeView
        {
            get 
            {
                ItemsControl parent = ParentItemsControl; 
                while (parent != null) 
                {
                    TreeView tv = parent as TreeView; 
                    if (tv != null)
                    {
                        return tv;
                    } 

                    parent = ItemsControl.ItemsControlFromItemContainer(parent); 
                } 

                return null; 
            }
        }

        ///  
        ///     Returns the immediate parent TreeViewItem. Null if the parent is a TreeView.
        ///  
        internal TreeViewItem ParentTreeViewItem 
        {
            get 
            {
                return ParentItemsControl as TreeViewItem;
            }
        } 

        ///  
        ///     Returns the immediate parent ItemsControl. 
        /// 
        internal ItemsControl ParentItemsControl 
        {
            get
            {
                return ItemsControl.ItemsControlFromItemContainer(this); 
            }
        } 
 
        #endregion
 
        #region Selection

        /// 
        /// Called when the visual parent of this element changes. 
        /// 
        ///  
        protected internal override void OnVisualParentChanged(DependencyObject oldParent) 
        {
            // When TreeViewItem is added to the visual tree we check if IsSelected is set to true 
            // In this case we need to update the tree selection
            if (VisualTreeHelper.GetParent(this) != null)
            {
                if (IsSelected) 
                {
                    Select(true); 
                } 
            }
 
            base.OnVisualParentChanged(oldParent);
        }

        private void Select(bool selected) 
        {
            TreeView tree = ParentTreeView; 
            ItemsControl parent = ParentItemsControl; 
            if ((tree != null) && (parent != null) && !tree.IsSelectionChangeActive)
            { 
                // Give the TreeView a reference to this container and its data
                object data = parent.GetItemOrContainerFromContainer(this);
                tree.ChangeSelection(data, this, selected);
            } 
        }
 
        private bool ContainsSelection 
        {
            get { return ReadControlFlag(ControlBoolFlags.ContainsSelection); } 
            set { WriteControlFlag(ControlBoolFlags.ContainsSelection, value); }
        }

        internal void UpdateContainsSelection(bool selected) 
        {
            TreeViewItem parent = ParentTreeViewItem; 
            while (parent != null) 
            {
                parent.ContainsSelection = selected; 
                parent = parent.ParentTreeViewItem;
            }
        }
 
        #endregion
 
        #region Input 

        ///  
        ///     This method is invoked when the IsFocused property changes to true.
        /// 
        /// Event arguments.
        protected override void OnGotFocus(RoutedEventArgs e) 
        {
            Select(true); 
            base.OnGotFocus(e); 
        }
 
        /// 
        ///     Called when the left mouse button is pressed down.
        /// 
        /// Event arguments 
        protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e)
        { 
            if (!e.Handled && IsEnabled) 
            {
                if (Focus()) 
                {
                    e.Handled = true;
                }
 
                if ((e.ClickCount % 2) == 0)
                { 
                    IsExpanded = !IsExpanded; 
                    e.Handled = true;
                } 
            }
            base.OnMouseLeftButtonDown(e);
        }
 
        /// 
        ///     Called when a keyboard key is pressed down. 
        ///  
        /// Event Arguments
        protected override void OnKeyDown(KeyEventArgs e) 
        {
            base.OnKeyDown(e);
            if (!e.Handled)
            { 
                switch (e.Key)
                { 
                    case Key.Add: 
                        if (CanExpandOnInput && !IsExpanded)
                        { 
                            IsExpanded = true;
                            e.Handled = true;
                        }
                        break; 

                    case Key.Subtract: 
                        if (CanExpandOnInput && IsExpanded) 
                        {
                            IsExpanded = false; 
                            e.Handled = true;
                        }
                        break;
 
                    case Key.Left:
                    case Key.Right: 
                        if (LogicalLeft(e.Key)) 
                        {
                            if (!IsControlKeyDown && CanExpandOnInput && IsExpanded) 
                            {
                                if (IsFocused)
                                {
                                    IsExpanded = false; 
                                }
                                else 
                                { 
                                    Focus();
                                } 
                                e.Handled = true;
                            }
                        }
                        else 
                        {
                            if (!IsControlKeyDown && CanExpandOnInput) 
                            { 
                                if (!IsExpanded)
                                { 
                                    IsExpanded = true;
                                    e.Handled = true;
                                }
                                else if (HandleDownKey()) 
                                {
                                    e.Handled = true; 
                                } 
                            }
                        } 
                        break;

                    case Key.Down:
                        if (!IsControlKeyDown && HandleDownKey()) 
                        {
                            e.Handled = true; 
                        } 
                        break;
 
                    case Key.Up:
                        if (!IsControlKeyDown && HandleUpKey())
                        {
                            e.Handled = true; 
                        }
                        break; 
                } 
            }
        } 

        private bool LogicalLeft(Key key)
        {
            bool invert = (FlowDirection == FlowDirection.RightToLeft); 
            return (!invert && (key == Key.Left)) || (invert && (key == Key.Right));
        } 
 
        private static bool IsControlKeyDown
        { 
            get
            {
                return ((Keyboard.Modifiers & ModifierKeys.Control) == (ModifierKeys.Control));
            } 
        }
 
        private bool CanExpandOnInput 
        {
            get 
            {
                return CanExpand && IsEnabled;
            }
        } 

        internal bool HandleUpKey() 
        { 
            if (AllowHandleKeyEvent(FocusNavigationDirection.Up))
            { 
                ItemsControl item = FindPreviousFocusableItem();

                if (item != null)
                { 
                    if (item == ParentItemsControl && item == ParentTreeView)
                    { 
                        return true; // Prevents KeyboardNavigation from focusing one of our children 
                    }
 
                    return item.Focus();
                }
            }
 
            return false; // Not handled
        } 
 
        internal bool HandleDownKey()
        { 
            if (AllowHandleKeyEvent(FocusNavigationDirection.Down))
            {
                return FocusDown();
            } 

            return false; // Not handled 
        } 

        private bool AllowHandleKeyEvent(FocusNavigationDirection direction) 
        {
            if (!IsSelected)
            {
                return false; 
            }
 
            DependencyObject currentFocus = Keyboard.FocusedElement as DependencyObject; 
            if (currentFocus != null && UIElementHelper.IsUIElementOrUIElement3D(currentFocus))
            { 
                DependencyObject predict = UIElementHelper.PredictFocus(currentFocus, direction);
                if (predict != currentFocus)
                {
                    while (predict != null) 
                    {
                        TreeViewItem item = predict as TreeViewItem; 
                        if (item == this) 
                        {
                            return false; // There is a focusable item in the header 
                        }
                        else if ((item != null) || (predict is TreeView))
                        {
                            return true; 
                        }
 
                        predict = VisualTreeHelper.GetParent(predict); 
                    }
                } 
            }

            return true;
        } 

        internal static bool FocusIntoItem(TreeViewItem item) 
        { 
            Debug.Assert(item.IsEnabled, "Only call FocusIntoItem with an enabled item");
 
            TreeViewItem lastItem = FindLastFocusableItem(item);

            if (lastItem != null)
            { 
                return lastItem.Focus();
            } 
 
            return false;
        } 

        internal bool FocusDown()
        {
            TreeViewItem item = FindNextFocusableItem(true); 

            if (item != null) 
            { 
                return item.Focus();
            } 

            return false;
        }
 

        ///  
        /// Returns the next item in the TreeView hierarchy, regardless of depth. 
        /// 
        ///  
        private TreeViewItem FindNextFocusableItem(bool walkIntoSubtree)
        {
            //
            // First walk into this item's subtree 
            //
 
            if (walkIntoSubtree && IsExpanded && CanExpand) 
            {
                TreeViewItem item = ItemContainerGenerator.ContainerFromIndex(0) as TreeViewItem; 
                if (item != null)
                {
                    if (item.IsEnabled)
                    { 
                        return item;
                    } 
                    else 
                    {
                        return item.FindNextFocusableItem(false); 
                    }
                }
            }
 
            //
            // Otherwise go to the next sibling 
            // 

            ItemsControl parent = ParentItemsControl; 
            if (parent != null)
            {
                TreeViewItem item;
                int index = parent.ItemContainerGenerator.IndexFromContainer(this); 
                int count = parent.Items.Count;
                while (index < count) 
                { 
                    // Find the next sibling
                    index++; 
                    item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem;
                    if ((item != null) && item.IsEnabled)
                    {
                        return item; 
                    }
                } 
 
                // This item has no next sibling, find the parent's next sibling
                item = parent as TreeViewItem; 
                if (item != null)
                {
                    return item.FindNextFocusableItem(false);
                } 
            }
 
            return null; // Not handled 
        }
 

        /// 
        /// Returns the previous item in the TreeView hierarchy, regardless of depth.
        ///  
        /// 
        private ItemsControl FindPreviousFocusableItem() 
        { 
            ItemsControl parent = ParentItemsControl;
            if (parent != null) 
            {
                int index = parent.ItemContainerGenerator.IndexFromContainer(this);
                while (index > 0)
                { 
                    index--;
                    TreeViewItem item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; 
                    if ((item != null) && item.IsEnabled) 
                    {
                        TreeViewItem lastItem = FindLastFocusableItem(item); 
                        if (lastItem != null)
                        {
                            return lastItem;
                        } 
                    }
                } 
 
                return parent;
            } 

            return null;
        }
 

        ///  
        /// Returns the last focusable item in the given subtree. 
        /// 
        ///  
        private static TreeViewItem FindLastFocusableItem(TreeViewItem item)
        {
            Debug.Assert(item.IsEnabled, "Only call FocusIntoItem with an enabled item");
 
            TreeViewItem lastItem = null;
 
            // Find the last child in the subtree. 
            int index = -1;
            TreeViewItem parent = null; 
            while (item != null)
            {
                if (item.IsEnabled)
                { 
                    if (!item.IsExpanded || !item.CanExpand)
                    { 
                        return item; 
                    }
 
                    lastItem = item;
                    parent = item;
                    index = item.Items.Count - 1;
                } 
                else if (index > 0)
                { 
                    index--; 
                }
                else 
                {
                    break;
                }
 
                item = parent.ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem;
            } 
 
            if (lastItem != null)
            { 
                return lastItem;
            }

            return null; 
        }
 
        ///  
        /// This should be PredictFocus but since UIElement.PredictFocus is sealed by FE we can't override it.
        /// TreeViewItem has its own code for deciding where focus should go. 
        /// 
        /// 
        /// 
        internal DependencyObject InternalPredictFocus(FocusNavigationDirection direction) 
        {
            switch (direction) 
            { 
                case FocusNavigationDirection.Left:
                case FocusNavigationDirection.Up: 
                    return FindPreviousFocusableItem();
                case FocusNavigationDirection.Right:
                case FocusNavigationDirection.Down:
                    return FindNextFocusableItem(true); 
                default:
                    return null; 
            } 

        } 


        private static void OnMouseButtonDown(object sender, MouseButtonEventArgs e)
        { 
            TreeViewItem tvi = (TreeViewItem)sender;
            TreeView tv = tvi.ParentTreeView; 
            if (tv != null) 
            {
                tv.HandleMouseButtonDown(); 
            }
        }
        private static void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
        { 
            if (e.TargetObject == sender)
            { 
                ((TreeViewItem)sender).HandleBringIntoView(e); 
            }
        } 

        private void HandleBringIntoView(RequestBringIntoViewEventArgs e)
        {
            TreeViewItem parent = ParentTreeViewItem; 
            while (parent != null)
            { 
                if (!parent.IsExpanded) 
                {
                    parent.IsExpanded = true; 
                }

                parent = parent.ParentTreeViewItem;
            } 

            // See FrameworkElement.BringIntoView() comments 
            //dmitryt, bug 1126518. On new/updated elements RenderSize isn't yet computed 
            //so we need to postpone the rect computation until layout is done.
            //this is accomplished by passing Empty rect here and then asking for RenderSize 
            //in IScrollInfo when it actually executes an async MakeVisible command.
            if (e.TargetRect.IsEmpty)
            {
                FrameworkElement header = HeaderElement; 
                if (header != null)
                { 
                    e.Handled = true; 
                    header.BringIntoView();
                } 
            }
        }

        private FrameworkElement HeaderElement 
        {
            get 
            { 
                return GetTemplateChild(HeaderPartName) as FrameworkElement;
            } 
        }

        internal bool HandleScrollByPage(bool up, ScrollViewer scroller, double viewportHeight, double startTop, double startBottom, out double currentDelta)
        { 
            double closeEdge;
            currentDelta = CalculateDelta(up, this, scroller, startTop, startBottom, out closeEdge); 
            if (DoubleUtil.GreaterThan(closeEdge, viewportHeight)) 
            {
                // The item does not fit in view at all 
                return false; // Did not focus
            }
            else if (DoubleUtil.LessThanOrClose(currentDelta, viewportHeight))
            { 
                // This item and all its children fit in view.
                // There may be others that also fit in view, so don't focus now 
                return false; // Did not focus 
            }
            else 
            {
                // This item is partially in view

                // Test if the header element is in view 
                bool headerInView = false;
                FrameworkElement header = HeaderElement; 
                if (header != null) 
                {
                    double delta = CalculateDelta(up, header, scroller, startTop, startBottom); 
                    if (DoubleUtil.LessThanOrClose(delta, viewportHeight))
                    {
                        // The header is in view
                        headerInView = true; 
                    }
                } 
 
                TreeViewItem select = null;
                int count = Items.Count; 
                bool skip = up && ContainsSelection;
                for (int index = (up ? count - 1 : 0); (0 <= index) && (index < count); index = index + (up ? -1 : 1))
                {
                    TreeViewItem item = ItemContainerGenerator.ContainerFromIndex(index) as TreeViewItem; 
                    if ((item != null) && item.IsEnabled)
                    { 
                        if (skip) 
                        {
                            if (item.IsSelected) 
                            {
                                skip = false;
                                continue; // Go to the next one
                            } 
                            else if (item.ContainsSelection)
                            { 
                                skip = false; 
                                // Look inside this one
                            } 
                            else
                            {
                                continue;
                            } 
                        }
 
                        double delta; 
                        if (item.HandleScrollByPage(up, scroller, viewportHeight, startTop, startBottom, out delta))
                        { 
                            // This item or one of its children was focused
                            return true;
                        }
                        else if (DoubleUtil.GreaterThan(delta, viewportHeight)) 
                        {
                            // This item does not fit 
                            break; 
                        }
                        else 
                        {
                            // This item does fit, but we should continue searching
                            select = item;
                        } 
                    }
                } 
 
                if (select != null)
                { 
                    // Earlier we found an item that fit but didn't focus it at that time
                    if (up)
                    {
                        return select.Focus(); 
                    }
                    else 
                    { 
                        return FocusIntoItem(select);
                    } 
                }
                else if (headerInView)
                {
                    // None of the children could be focused, the header is in view even though 
                    // the whole subtree isn't in view. There shouldn't be any more focusable
                    // items that fit, so select this one. 
                    return Focus(); 
                }
            } 

            return false; // Did not focus
        }
 
        private static double CalculateDelta(bool up, FrameworkElement item, ScrollViewer scroller, double startTop, double startBottom)
        { 
            double closeEdge; 
            return CalculateDelta(up, item, scroller, startTop, startBottom, out closeEdge);
        } 

        private static double CalculateDelta(bool up, FrameworkElement item, ScrollViewer scroller, double startTop, double startBottom, out double closeEdge)
        {
            double top, bottom; 
            GetTopAndBottom(item, scroller, out top, out bottom);
 
            if (up) 
            {
                closeEdge = startBottom - bottom; 
                return startBottom - top;
            }
            else
            { 
                closeEdge = top - startTop;
                return bottom - startTop; 
            } 
        }
 
        internal void GetTopAndBottom(Visual parent, out double top, out double bottom)
        {
            FrameworkElement header = HeaderElement;
            if (header != null) 
            {
                GetTopAndBottom(header, parent, out top, out bottom); 
            } 
            else
            { 
                GetTopAndBottom(this, parent, out top, out bottom);
            }
        }
 
        private static void GetTopAndBottom(FrameworkElement item, Visual parent, out double top, out double bottom)
        { 
            GeneralTransform transform = item.TransformToAncestor(parent); 

            Point upperLeft; 
            if (transform.TryTransform(new Point(0.0, 0.0), out upperLeft))
            {
                top = upperLeft.Y;
            } 
            else
            { 
                top = 0.0; 
            }
 
            Point lowerLeft;
            if (transform.TryTransform(new Point(0.0, item.RenderSize.Height), out lowerLeft))
            {
                bottom = lowerLeft.Y; 
            }
            else 
            { 
                bottom = top + item.RenderSize.Height;
            } 
        }

        #endregion
 
        #region Containers
 
 
        /// 
        ///     Returns true if the item is or should be its own container. 
        /// 
        /// The item to test.
        /// true if its type matches the container type.
        protected override bool IsItemItsOwnContainerOverride(object item) 
        {
            return item is TreeViewItem; 
        } 

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

 
        /// 
        /// We only override this to help with container estimation for virtualization
        /// 
        ///  
        /// 
        protected override Size MeasureOverride(Size constraint) 
        { 
            Size desiredSize = base.MeasureOverride(constraint);
 
            if (IsVirtualizing && !IsExpanded && IsVisible)
            {
                TreeView parent = ParentTreeView;
 
                if (parent != null)
                { 
                    parent.RegisterContainerSize(IsLogicalHorizontal ? desiredSize.Width : desiredSize.Height); 
                }
            } 

            return desiredSize;
        }
 
        /// 
        /// Send down the IsVirtualizing property if it's set on this element. 
        ///  
        /// 
        ///  
        protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
        {
            base.PrepareContainerForItemOverride(element, item);
            IsVirtualizingPropagationHelper(this, element); 
        }
 
        // Synchronizes the value of the child's IsVirtualizing property with that of the parent's 
        internal static void IsVirtualizingPropagationHelper(DependencyObject parent, DependencyObject element)
        { 
            SynchronizeValue(VirtualizingStackPanel.IsVirtualizingProperty, parent, element);
            SynchronizeValue(VirtualizingStackPanel.VirtualizationModeProperty, parent, element);

        } 

        private static void SynchronizeValue(DependencyProperty dp, DependencyObject parent, DependencyObject child) 
        { 
            if (IsDefaultValue(dp, parent))
            { 
                child.ClearValue(dp);
            }
            else
            { 
                object value = parent.GetValue(dp);
                child.SetValue(dp, value); 
            } 
        }
 
        private static bool IsDefaultValue(DependencyProperty dp, DependencyObject element)
        {
            bool hasModifiers;
            return element.GetValueSource(dp, null, out hasModifiers) == BaseValueSourceInternal.Default; 
        }
 
        ///  
        ///     This method is invoked when the Items property changes.
        ///  
        protected override void OnItemsChanged(NotifyCollectionChangedEventArgs e)
        {
            switch (e.Action)
            { 
                case NotifyCollectionChangedAction.Remove:
                case NotifyCollectionChangedAction.Reset: 
                    if (ContainsSelection) 
                    {
                        TreeView tree = ParentTreeView; 
                        if ((tree != null) && !tree.IsSelectedContainerHookedUp)
                        {
                            ContainsSelection = false;
                            Select(true); 
                        }
                    } 
                    break; 

                case NotifyCollectionChangedAction.Replace: 
                    if (ContainsSelection)
                    {
                        TreeView tree = ParentTreeView;
                        if (tree != null) 
                        {
                            // When Selected item is replaced - remove the selection 
                            // Revisit the condition when we support duplicate items in Items collection: if e.OldItems[0] is the same as selected items we will unselect the selected item 
                            object selectedItem = tree.SelectedItem;
                            if ((selectedItem != null) && selectedItem.Equals(e.OldItems[0])) 
                            {
                                tree.ChangeSelection(selectedItem, tree.SelectedContainer, false);
                            }
                        } 
                    }
                    break; 
 
                case NotifyCollectionChangedAction.Add:
                case NotifyCollectionChangedAction.Move: 
                    break;

                default:
                    throw new NotSupportedException(SR.Get(SRID.UnexpectedCollectionChangeAction, e.Action)); 
            }
        } 
 
        #endregion
 
        #region Automation
        /// 
        /// Creates AutomationPeer ()
        ///  
        protected override AutomationPeer OnCreateAutomationPeer()
        { 
            return new TreeViewItemAutomationPeer(this); 
        }
        #endregion Automation 

        #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 

        #endregion 
 
        #region Data
 
        private const string HeaderPartName = "PART_Header";

        #endregion
    } 
}
 

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