TreeViewItem.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 / TreeViewItem.cs / 1305600 / 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 System.Windows.Threading; 
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));
 
            IsMouseOverPropertyKey.OverrideMetadata(typeof(TreeViewItem), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged)));
            IsEnabledProperty.OverrideMetadata(typeof(TreeViewItem), new UIPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged))); 
            Selector.IsSelectionActivePropertyKey.OverrideMetadata(typeof(TreeViewItem), new FrameworkPropertyMetadata(new PropertyChangedCallback(OnVisualStatePropertyChanged))); 

            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));
            } 
 
            item.UpdateVisualState();
        } 

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

            item.UpdateVisualState();
        }
 
        /// 
        ///     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 Public Methods
 
        ///  
        /// Expands this TreeViewItem and all of the TreeViewItems inside its subtree.
        ///  
        public void ExpandSubtree()
        {
            ExpandRecursive(this);
        } 

        #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); 
 
                // Making focus of TreeViewItem synchronize with selection if needed.
                if (selected && tree.IsKeyboardFocusWithin && !IsKeyboardFocusWithin) 
                {
                    Focus();
                }
            } 
        }
 
        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)
                { 
                    SetCurrentValueInternal(IsExpandedProperty, BooleanBoxes.Box(!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)
                        { 
                            SetCurrentValueInternal(IsExpandedProperty, BooleanBoxes.TrueBox);
                            e.Handled = true;
                        }
                        break; 

                    case Key.Subtract: 
                        if (CanExpandOnInput && IsExpanded) 
                        {
                            SetCurrentValueInternal(IsExpandedProperty, BooleanBoxes.FalseBox); 
                            e.Handled = true;
                        }
                        break;
 
                    case Key.Left:
                    case Key.Right: 
                        if (LogicalLeft(e.Key)) 
                        {
                            if (!IsControlKeyDown && CanExpandOnInput && IsExpanded) 
                            {
                                if (IsFocused)
                                {
                                    SetCurrentValueInternal(IsExpandedProperty, BooleanBoxes.FalseBox); 
                                }
                                else 
                                { 
                                    Focus();
                                } 
                                e.Handled = true;
                            }
                        }
                        else 
                        {
                            if (!IsControlKeyDown && CanExpandOnInput) 
                            { 
                                if (!IsExpanded)
                                { 
                                    SetCurrentValueInternal(IsExpandedProperty, BooleanBoxes.TrueBox);
                                    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.SetCurrentValueInternal(IsExpandedProperty, BooleanBoxes.TrueBox); 
                }

                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();
                } 
                else
                {
                    // Header is not generated yet. Could happen if BringIntoView is called on container before layout. Try later.
                    Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(BringItemIntoView), null); 
                }
            } 
        } 

        private object BringItemIntoView(object args) 
        {
            FrameworkElement header = HeaderElement;
            if (header != null)
            { 
                header.BringIntoView();
            } 
            return null; 
        }
 
        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));
            }
        }
 
        /// 
        /// Recursively & syncronously expand all the nodes in this subtree. 
        ///  
        private static void ExpandRecursive(TreeViewItem item)
        { 
            if (item == null)
            {
                return;
            } 

            // Expand the current item 
            if (!item.IsExpanded) 
            {
                item.SetCurrentValueInternal(IsExpandedProperty, BooleanBoxes.TrueBox); 
            }

            // ApplyTemplate in order to generate the ItemsPresenter and the ItemsPanel. Note that in the
            // virtualizing case even if the item is marked expanded we still need to do this step in order to 
            // regenerate the visuals because they may have been virtualized away.
 
            item.ApplyTemplate(); 
            ItemsPresenter itemsPresenter = (ItemsPresenter)item.Template.FindName("ItemsHost", item);
            if (itemsPresenter != null) 
            {
                itemsPresenter.ApplyTemplate();
            }
            else 
            {
                item.UpdateLayout(); 
            } 

            VirtualizingPanel virtualizingPanel = item.ItemsHost as VirtualizingPanel; 
            item.ItemsHost.EnsureGenerator();

            for (int i = 0, count = item.Items.Count; i < count; i++)
            { 
                TreeViewItem subitem;
                if (virtualizingPanel != null) 
                { 
                    // We need to bring the item into view so that the container will be generated.
                    virtualizingPanel.BringIndexIntoView(i); 

                    subitem = (TreeViewItem)item.ItemContainerGenerator.ContainerFromIndex(i);
                }
                else 
                {
                    subitem = (TreeViewItem)item.ItemContainerGenerator.ContainerFromIndex(i); 
 
                    // We dont actually need to bring this into view, but we'll do it
                    // anyways to maintain the same behavior as with a virtualizing panel. 
                    subitem.BringIntoView();
                }

                if (subitem != null) 
                {
                    ExpandRecursive(subitem); 
                } 
            }
        } 

        #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 Visual States

        internal override void ChangeVisualState(bool useTransitions) 
        {
            // Handle the Common states 
            if (!IsEnabled) 
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateDisabled, VisualStates.StateNormal); 
            }
            else if (IsMouseOver)
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateMouseOver, VisualStates.StateNormal); 
            }
            else 
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateNormal);
            } 

            // Handle the Focused states
            if (IsKeyboardFocused)
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateFocused, VisualStates.StateUnfocused);
            } 
            else 
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateUnfocused); 
            }

            // Handle the Expansion states
            if (IsExpanded) 
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateExpanded); 
            } 
            else
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateCollapsed);
            }

            // Handle the HasItems states 
            if (HasItems)
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateHasItems); 
            }
            else 
            {
                VisualStates.GoToState(this, useTransitions, VisualStates.StateNoItems);
            }
 
            // Handle the Selected states
            if (IsSelected) 
            { 
                if (IsSelectionActive)
                { 
                    VisualStates.GoToState(this, useTransitions, VisualStates.StateSelected);
                }
                else
                { 
                    VisualStates.GoToState(this, useTransitions, VisualStates.StateSelectedInactive, VisualStates.StateSelected);
                } 
            } 
            else
            { 
                VisualStates.GoToState(this, useTransitions, VisualStates.StateUnselected);
            }

            base.ChangeVisualState(useTransitions); 
        }
 
        #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