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

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- WebBrowserContainer.cs
- TdsRecordBufferSetter.cs
- ExpressionNode.cs
- URLString.cs
- WindowsUserNameCachingSecurityTokenAuthenticator.cs
- FactoryGenerator.cs
- IMembershipProvider.cs
- StringUtil.cs
- ConfigurationSchemaErrors.cs
- SiteMapPath.cs
- OutputCacheProfile.cs
- WorkflowRuntimeServicesBehavior.cs
- PagerSettings.cs
- TypeReference.cs
- Accessible.cs
- StyleSelector.cs
- QueryOperatorEnumerator.cs
- PropagationProtocolsTracing.cs
- TCPListener.cs
- DesignTimeVisibleAttribute.cs
- MetafileHeader.cs
- SelectionProviderWrapper.cs
- WindowsHyperlink.cs
- CategoryAttribute.cs
- DiagnosticTrace.cs
- ProfileGroupSettingsCollection.cs
- LinqDataSourceUpdateEventArgs.cs
- Operator.cs
- __Filters.cs
- TextSelectionHighlightLayer.cs
- FormCollection.cs
- DataGridViewHeaderCell.cs
- XmlSchema.cs
- SqlInternalConnection.cs
- QueryOutputWriter.cs
- MetadataCollection.cs
- EmptyEnumerator.cs
- BitVector32.cs
- WebPartCollection.cs
- ApplyImportsAction.cs
- DataColumnCollection.cs
- FrameworkTextComposition.cs
- ZipIORawDataFileBlock.cs
- WizardForm.cs
- MiniCustomAttributeInfo.cs
- SqlTypesSchemaImporter.cs
- ScrollableControlDesigner.cs
- UIPropertyMetadata.cs
- UTF32Encoding.cs
- IPipelineRuntime.cs
- Rotation3DAnimationBase.cs
- BasicKeyConstraint.cs
- EdmTypeAttribute.cs
- SerializableTypeCodeDomSerializer.cs
- SpanIndex.cs
- Calendar.cs
- LocalizableAttribute.cs
- EditorPartChrome.cs
- Normalization.cs
- CodeTypeOfExpression.cs
- RuleSetDialog.Designer.cs
- TrackingProfile.cs
- GraphicsContext.cs
- WindowsListViewGroupSubsetLink.cs
- AssemblyResourceLoader.cs
- ColorPalette.cs
- ScriptModule.cs
- MultiDataTrigger.cs
- ButtonChrome.cs
- Debug.cs
- RelationshipSet.cs
- XmlSchemaSimpleContentExtension.cs
- SingleObjectCollection.cs
- XsltException.cs
- printdlgexmarshaler.cs
- ApplicationManager.cs
- PrincipalPermission.cs
- HttpHandler.cs
- StsCommunicationException.cs
- DbParameterHelper.cs
- GlyphsSerializer.cs
- NameScope.cs
- Model3DCollection.cs
- SafeUserTokenHandle.cs
- MeasurementDCInfo.cs
- TextBlock.cs
- AutoGeneratedFieldProperties.cs
- QueryOperatorEnumerator.cs
- TreeWalkHelper.cs
- GatewayDefinition.cs
- WindowHideOrCloseTracker.cs
- WindowShowOrOpenTracker.cs
- ExportException.cs
- Point3DAnimation.cs
- RecognizedPhrase.cs
- SessionEndingCancelEventArgs.cs
- XmlText.cs
- WebScriptServiceHost.cs
- OdbcParameter.cs
- UnionCodeGroup.cs