Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / Orcas / SP / wpf / src / Framework / System / Windows / Controls / ListBox.cs / 1 / ListBox.cs
//----------------------------------------------------------------------------
//
// Copyright (C) Microsoft Corporation. All rights reserved.
//
//---------------------------------------------------------------------------
using MS.Internal;
using MS.Utility;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Windows.Automation.Peers;
using System;
using MS.Internal.Commands; // CommandHelpers
using MS.Internal.KnownBoxes;
namespace System.Windows.Controls
{
///
/// Control that implements a list of selectable items.
///
[Localizability(LocalizationCategory.ListBox)]
[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(ListBoxItem))]
public class ListBox : Selector
{
//-------------------------------------------------------------------
//
// Constructors
//
//-------------------------------------------------------------------
#region Constructors
///
/// Default DependencyObject constructor
///
///
/// Automatic determination of current Dispatcher. Use alternative constructor
/// that accepts a Dispatcher for best performance.
///
public ListBox() : base()
{
Initialize();
}
// common code for all constructors
private void Initialize()
{
SelectionMode mode = (SelectionMode) SelectionModeProperty.GetDefaultValue(DependencyObjectType);
ValidateSelectionMode(mode);
}
static ListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox)));
_dType = DependencyObjectType.FromSystemTypeInternal(typeof(ListBox));
IsTabStopProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(KeyboardNavigationMode.Contained));
KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once));
IsTextSearchEnabledProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(BooleanBoxes.TrueBox));
ItemsPanelTemplate template = new ItemsPanelTemplate(new FrameworkElementFactory(typeof(VirtualizingStackPanel)));
template.Seal();
ItemsPanelProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(template));
// Need handled events too here because any mouse up should release our mouse capture
EventManager.RegisterClassHandler(typeof(ListBox), Mouse.MouseUpEvent, new MouseButtonEventHandler(OnMouseButtonUp), true);
EventManager.RegisterClassHandler(typeof(ListBox), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnGotKeyboardFocus));
CommandHelpers.RegisterCommandHandler(typeof(ListBox), ListBox.SelectAllCommand, new ExecutedRoutedEventHandler(OnSelectAll), new CanExecuteRoutedEventHandler(OnQueryStatusSelectAll), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.ListBoxSelectAllKey), SR.Get(SRID.ListBoxSelectAllKeyDisplayString)));
}
#endregion
//--------------------------------------------------------------------
//
// Public Methods
//
//-------------------------------------------------------------------
#region Public Methods
///
/// Select all the items
///
public void SelectAll()
{
if (CanSelectMultiple)
{
SelectAllImpl();
}
else
{
throw new NotSupportedException(SR.Get(SRID.ListBoxSelectAllSelectionMode));
}
}
///
/// Clears all of the selected items.
///
public void UnselectAll()
{
UnselectAllImpl();
}
///
/// Causes the object to scroll into view. If it is not visible, it is aligned either at the top or bottom of the viewport.
///
///
public void ScrollIntoView(object item)
{
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
OnBringItemIntoView(item);
}
else
{
// The items aren't generated, try at a later time
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(OnBringItemIntoView), item);
}
}
private object OnBringItemIntoView(object arg)
{
FrameworkElement element = ItemContainerGenerator.ContainerFromItem(arg) as FrameworkElement;
if (element != null)
{
element.BringIntoView();
}
else if (!IsGrouping && Items.Contains(arg))
{
// We might be virtualized, try to de-virtualize the item.
// Note: There is opportunity here to make a public OM.
VirtualizingPanel itemsHost = ItemsHost as VirtualizingPanel;
if (itemsHost != null)
{
itemsHost.BringIndexIntoView(Items.IndexOf(arg));
}
}
return null;
}
#endregion
//--------------------------------------------------------------------
//
// Public Properties
//
//--------------------------------------------------------------------
#region Public Properties
///
/// SelectionMode DependencyProperty
///
public static readonly DependencyProperty SelectionModeProperty =
DependencyProperty.Register(
"SelectionMode",
typeof(SelectionMode),
typeof(ListBox),
new FrameworkPropertyMetadata(
SelectionMode.Single,
new PropertyChangedCallback(OnSelectionModeChanged)),
new ValidateValueCallback(IsValidSelectionMode));
///
/// Indicates the selection behavior for the ListBox.
///
public SelectionMode SelectionMode
{
get { return (SelectionMode) GetValue(SelectionModeProperty); }
set { SetValue(SelectionModeProperty, value); }
}
private static void OnSelectionModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ListBox listBox = (ListBox)d;
listBox.ValidateSelectionMode(listBox.SelectionMode);
}
private static object OnGetSelectionMode(DependencyObject d)
{
return ((ListBox)d).SelectionMode;
}
private static bool IsValidSelectionMode(object o)
{
SelectionMode value = (SelectionMode)o;
return value == SelectionMode.Single
|| value == SelectionMode.Multiple
|| value == SelectionMode.Extended;
}
private void ValidateSelectionMode(SelectionMode mode)
{
CanSelectMultiple = (mode != SelectionMode.Single);
}
///
/// A read-only IList containing the currently selected items
///
public static readonly DependencyProperty SelectedItemsProperty = Selector.SelectedItemsImplProperty;
///
/// The currently selected items.
///
[Bindable(true), Category("Appearance"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IList SelectedItems
{
get
{
return SelectedItemsImpl;
}
}
#endregion
//-------------------------------------------------------------------
//
// Protected Methods
//
//--------------------------------------------------------------------
#region Protected Methods
///
/// Creates AutomationPeer ( )
///
protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
{
return new System.Windows.Automation.Peers.ListBoxAutomationPeer(this);
}
///
/// Select multiple items.
///
/// Collection of items to be selected.
/// true if all items have been selected.
protected bool SetSelectedItems(IEnumerable selectedItems)
{
return SetSelectedItemsImpl(selectedItems);
}
///
/// Prepare the element to display the item. This may involve
/// applying styles, setting bindings, etc.
///
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
if (item is Separator)
Separator.PrepareContainer(element as Control);
}
///
/// A virtual function that is called when the selection is changed. Default behavior
/// is to raise a SelectionChangedEvent
///
/// The inputs for this event. Can be raised (default behavior) or processed
/// in some other way.
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
// In a single selection mode we want to move anchor to the selected element
if (SelectionMode == SelectionMode.Single && SelectedItem != null)
{
ListBoxItem listItem = SelectedItem as ListBoxItem;
if (listItem == null)
listItem = ItemContainerGenerator.ContainerFromItem(SelectedItem) as ListBoxItem;
if (listItem != null)
UpdateAnchorAndActionItem(listItem);
}
if ( AutomationPeer.ListenerExists(AutomationEvents.SelectionPatternOnInvalidated)
|| AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementSelected)
|| AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementAddedToSelection)
|| AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection) )
{
ListBoxAutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(this) as ListBoxAutomationPeer;
if (peer != null)
peer.RaiseSelectionEvents(e);
}
}
///
/// This is the method that responds to the KeyDown event.
///
/// Event Arguments
protected override void OnKeyDown(KeyEventArgs e)
{
bool handled = true;
Key key = e.Key;
switch (key)
{
case Key.Divide:
case Key.Oem2:
// Ctrl-Fowardslash = Select All
if (((Keyboard.Modifiers & ModifierKeys.Control) == (ModifierKeys.Control)) && (SelectionMode == SelectionMode.Extended))
{
SelectAll();
}
else
{
handled = false;
}
break;
case Key.Oem5:
// Ctrl-Backslash = Select the item with focus.
if (((Keyboard.Modifiers & ModifierKeys.Control) == (ModifierKeys.Control)) && (SelectionMode == SelectionMode.Extended))
{
ListBoxItem focusedItemUI = ItemContainerGenerator.ContainerFromItem(FocusedItem) as ListBoxItem;
if (focusedItemUI != null)
{
MakeSingleSelection(focusedItemUI);
}
}
else
{
handled = false;
}
break;
case Key.Up:
case Key.Left:
case Key.Down:
case Key.Right:
{
KeyboardNavigation.ShowFocusVisual();
// Depend on logical orientation we decide to move focus or just scroll
// shouldScroll also detects if we can scroll more in this direction
bool shouldScroll = ScrollHost != null;
if (shouldScroll)
{
shouldScroll =
((key == Key.Down && IsLogicalHorizontal && DoubleUtil.GreaterThan(ScrollHost.ScrollableHeight, ScrollHost.VerticalOffset))) ||
((key == Key.Up && IsLogicalHorizontal && DoubleUtil.GreaterThan(ScrollHost.VerticalOffset, 0d))) ||
((key == Key.Right&& IsLogicalVertical && DoubleUtil.GreaterThan(ScrollHost.ScrollableWidth, ScrollHost.HorizontalOffset))) ||
((key == Key.Left && IsLogicalVertical && DoubleUtil.GreaterThan(ScrollHost.HorizontalOffset, 0d)));
}
if (shouldScroll)
{
ScrollHost.ScrollInDirection(e);
}
else
{
ListBoxItem listBoxItem = e.OriginalSource as ListBoxItem;
// Handle arrow keys only if the event source is ListBoxItem or ListBox itself
if (listBoxItem != null && ItemsControlFromItemContainer(listBoxItem) == this)
{
// Navigate focus from current ListBoxItem
if (!listBoxItem.MoveFocus(new TraversalRequest(KeyboardNavigation.KeyToTraversalDirection(key))))
handled = false;
}
else
{
if (e.OriginalSource == this)
NavigateToStart(ItemNavigateArgs.Empty);
else
handled = false;
}
}
}
break;
case Key.Home:
NavigateToStart(new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
break;
case Key.End:
NavigateToEnd(new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
break;
case Key.Space:
case Key.Enter:
{
if (e.Key == Key.Enter && (bool)GetValue(KeyboardNavigation.AcceptsReturnProperty) == false)
{
handled = false;
break;
}
// If the event came from a ListBoxItem that's a child of ours, then look at it.
ListBoxItem source = e.OriginalSource as ListBoxItem;
// If ALT is down & Ctrl is up, then we shouldn't handle this. (system menu)
if ((Keyboard.Modifiers & (ModifierKeys.Control|ModifierKeys.Alt)) == ModifierKeys.Alt)
{
handled = false;
break;
}
// If the user hits just "space" while text searching, do not handle the event
// Note: Space cannot be the first character in a string sent to ITS.
if (IsTextSearchEnabled && Keyboard.Modifiers == ModifierKeys.None)
{
TextSearch instance = TextSearch.EnsureInstance(this);
// If TextSearch enabled and Prefix is not empty
// then let this SPACE go so ITS can process it.
if (instance != null && (instance.GetCurrentPrefix() != String.Empty))
{
handled = false;
break;
}
}
if (source != null && ItemsControlFromItemContainer(source) == this)
{
switch (SelectionMode)
{
case SelectionMode.Single:
if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
MakeToggleSelection(source);
}
else
{
MakeSingleSelection(source);
}
break;
case SelectionMode.Multiple:
MakeToggleSelection(source);
break;
case SelectionMode.Extended:
if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == ModifierKeys.Control)
{
// Only CONTROL
MakeToggleSelection(source);
}
else if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == ModifierKeys.Shift)
{
// Only SHIFT
MakeAnchorSelection(source, true /* clearCurrent */);
}
else if ((Keyboard.Modifiers & ModifierKeys.Shift) == 0)
{
MakeSingleSelection(source);
}
else
{
handled = false;
}
break;
}
}
else
{
handled = false;
}
}
break;
case Key.PageUp:
NavigateByPage(FocusNavigationDirection.Up, new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
break;
case Key.PageDown:
NavigateByPage(FocusNavigationDirection.Down, new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
break;
default:
handled = false;
break;
}
if (handled)
{
e.Handled = true;
}
else
{
base.OnKeyDown(e);
}
}
///
/// An event reporting a mouse move.
///
protected override void OnMouseMove(MouseEventArgs e)
{
// If we get a mouse move and we have capture, then the mouse was
// outside the ListBox. We should autoscroll.
if (e.OriginalSource == this && Mouse.Captured == this)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
DoAutoScroll();
}
else
{
// We missed the mouse up, release capture
ReleaseMouseCapture();
ResetLastMousePosition();
}
}
base.OnMouseMove(e);
}
private static void OnMouseButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
ListBox listBox = (ListBox)sender;
listBox.ReleaseMouseCapture();
listBox.ResetLastMousePosition();
}
}
private static void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
ListBox listbox = (ListBox)sender;
// Focus drives the selection when keyboardnavigation is used
if (!KeyboardNavigation.IsKeyboardMostRecentInputDevice())
return;
// Only in case focus moves from one ListBoxItem to another we want the selection to follow focus
ListBoxItem newListBoxItem = e.NewFocus as ListBoxItem;
if (newListBoxItem != null && ItemsControlFromItemContainer(newListBoxItem) == listbox)
{
DependencyObject oldFocus = e.OldFocus as DependencyObject;
Visual visualOldFocus = oldFocus as Visual;
if (visualOldFocus == null)
{
ContentElement ce = oldFocus as ContentElement;
if (ce != null)
visualOldFocus = KeyboardNavigation.GetParentUIElementFromContentElement(ce);
}
if ((visualOldFocus != null && listbox.IsAncestorOf(visualOldFocus))
|| oldFocus == listbox)
{
listbox.LastActionItem = newListBoxItem;
listbox.MakeKeyboardSelection(newListBoxItem);
}
}
}
///
/// Called when IsMouseCaptured changes on this element.
///
///
protected override void OnIsMouseCapturedChanged(DependencyPropertyChangedEventArgs e)
{
// When we take capture, we should start a timer to call
// us back and do auto scrolling behavior.
if (IsMouseCaptured)
{
Debug.Assert(_autoScrollTimer == null, "IsMouseCaptured went from true to true");
if (_autoScrollTimer == null)
{
_autoScrollTimer = new DispatcherTimer(DispatcherPriority.SystemIdle);
_autoScrollTimer.Interval = AutoScrollTimeout;
_autoScrollTimer.Tick += new EventHandler(OnAutoScrollTimeout);
_autoScrollTimer.Start();
}
}
else
{
if (_autoScrollTimer != null)
{
_autoScrollTimer.Stop();
_autoScrollTimer = null;
}
}
base.OnIsMouseCapturedChanged(e);
}
///
/// Return true if the item is (or is eligible to be) its own ItemContainer
///
protected override bool IsItemItsOwnContainerOverride(object item)
{
return (item is ListBoxItem);
}
/// Create or identify the element used to display the given item.
protected override DependencyObject GetContainerForItemOverride()
{
return new ListBoxItem();
}
///
/// If control has a scrollviewer in its style and has a custom keyboard scrolling behavior when HandlesScrolling should return true.
/// Then ScrollViewer will not handle keyboard input and leave it up to the control.
///
protected internal override bool HandlesScrolling
{
get
{
return true;
}
}
#endregion
//-------------------------------------------------------------------
//
// Private Methods
//
//-------------------------------------------------------------------
#region Private Methods
private static void OnQueryStatusSelectAll(object target, CanExecuteRoutedEventArgs args)
{
ListBox listBox = target as ListBox;
if (listBox.SelectionMode == SelectionMode.Extended)
{
args.CanExecute = true;
}
}
private static void OnSelectAll(object target, ExecutedRoutedEventArgs args)
{
ListBox listBox = target as ListBox;
if (listBox.SelectionMode == SelectionMode.Extended)
{
listBox.SelectAll();
}
}
internal void NotifyListItemClicked(ListBoxItem item, MouseButton mouseButton)
{
// When a ListBoxItem is left clicked, we should take capture
// so we can auto scroll through the list.
if (mouseButton == MouseButton.Left && Mouse.Captured != this)
{
Mouse.Capture(this, CaptureMode.SubTree);
SetInitialMousePosition(); // Start tracking mouse movement
}
switch (SelectionMode)
{
case SelectionMode.Single:
{
if (!item.IsSelected)
{
item.IsSelected = true;
}
else if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
item.IsSelected = false;
}
UpdateAnchorAndActionItem(item);
}
break;
case SelectionMode.Multiple:
MakeToggleSelection(item);
break;
case SelectionMode.Extended:
// Extended selection works only with Left mouse button
if (mouseButton == MouseButton.Left)
{
if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == (ModifierKeys.Control | ModifierKeys.Shift))
{
MakeAnchorSelection(item, false);
}
else if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
MakeToggleSelection(item);
}
else if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
{
MakeAnchorSelection(item, true);
}
else
{
MakeSingleSelection(item);
}
}
else if (mouseButton == MouseButton.Right) // Right mouse button
{
// Shift or Control combination should not trigger any action
// If only Right mouse button is pressed we should move the anchor
// and select the item only if element under the mouse is not selected
if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == 0)
{
if (item.IsSelected)
UpdateAnchorAndActionItem(item);
else
MakeSingleSelection(item);
}
}
break;
}
}
internal void NotifyListItemMouseDragged(ListBoxItem listItem)
{
if ((Mouse.Captured == this) && DidMouseMove())
{
NavigateToItem(ItemContainerGenerator.ItemFromContainer(listItem), new ItemNavigateArgs(Mouse.PrimaryDevice, Keyboard.Modifiers));
}
}
private void UpdateAnchorAndActionItem(ListBoxItem listItem)
{
object item = ItemContainerGenerator.ItemFromContainer(listItem);
if (item == DependencyProperty.UnsetValue)
{
AnchorItem = null;
LastActionItem = null;
}
else
{
AnchorItem = item;
LastActionItem = listItem;
}
KeyboardNavigation.SetTabOnceActiveElement(this, listItem);
}
private void MakeSingleSelection(ListBoxItem listItem)
{
if (ItemsControlFromItemContainer(listItem) == this)
{
object item = ItemContainerGenerator.ItemFromContainer(listItem);
SelectionChange.SelectJustThisItem(item, true /* assumeInItemsCollection */);
listItem.Focus();
UpdateAnchorAndActionItem(listItem);
}
}
private void MakeToggleSelection(ListBoxItem item)
{
bool select = !item.IsSelected;
item.IsSelected = select;
UpdateAnchorAndActionItem(item);
}
private void MakeAnchorSelection(ListBoxItem actionItem, bool clearCurrent)
{
if (AnchorItem == null)
{
if (_selectedItems.Count > 0)
{
// If we haven't set the anchor, then just use the last selected item
AnchorItem = _selectedItems[_selectedItems.Count - 1];
}
else
{
// There was nothing selected, so take the first child element
AnchorItem = Items[0];
}
if (AnchorItem == null)
{
// Can't do anything
return;
}
}
// Find the indexes of the elements
int start, end;
start = ElementIndex(actionItem);
end = Items.IndexOf(AnchorItem);
// Ensure start is before end
if (start > end)
{
int index = start;
start = end;
end = index;
}
bool beganSelectionChange = false;
if (!SelectionChange.IsActive)
{
beganSelectionChange = true;
SelectionChange.Begin();
}
try
{
if (clearCurrent)
{
// Unselect items not within the selection range
for (int index = 0; index < _selectedItems.Count; index++)
{
object item = _selectedItems[index];
int itemIndex = Items.IndexOf(item);
if ((itemIndex < start) || (end < itemIndex))
{
SelectionChange.Unselect(item);
}
}
}
// Select the children in the selection range
IEnumerator enumerator = ((IEnumerable)Items).GetEnumerator();
for (int index = 0; index <= end; index++)
{
enumerator.MoveNext();
if (index >= start)
{
SelectionChange.Select(enumerator.Current, true /* assumeInItemsCollection */);
}
}
}
finally
{
if (beganSelectionChange)
{
SelectionChange.End();
}
}
LastActionItem = actionItem;
}
private void MakeKeyboardSelection(ListBoxItem item)
{
if (item == null)
{
return;
}
switch (SelectionMode)
{
case SelectionMode.Single:
// Navigating when control is down shouldn't select the item
if ((Keyboard.Modifiers & ModifierKeys.Control) == 0)
{
MakeSingleSelection(item);
}
break;
case SelectionMode.Multiple:
UpdateAnchorAndActionItem(item);
break;
case SelectionMode.Extended:
if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
{
bool clearCurrentSelection = (Keyboard.Modifiers & ModifierKeys.Control) == 0;
MakeAnchorSelection(item, clearCurrentSelection);
}
else if ((Keyboard.Modifiers & ModifierKeys.Control) == 0)
{
MakeSingleSelection(item);
}
break;
}
}
private int ElementIndex(ListBoxItem listItem)
{
return ItemContainerGenerator.IndexFromContainer(listItem);
}
private ListBoxItem ElementAt(int index)
{
return ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;
}
private object GetWeakReferenceTarget(ref WeakReference weakReference)
{
if (weakReference != null)
{
return weakReference.Target;
}
return null;
}
private void OnAutoScrollTimeout(object sender, EventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
DoAutoScroll();
}
}
///
/// Called when an item is being focused
///
internal override void FocusItem(object item, ItemNavigateArgs itemNavigateArgs)
{
// Base will actually focus the item
base.FocusItem(item, itemNavigateArgs);
ListBoxItem listItem = ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
if (listItem != null)
{
LastActionItem = listItem;
//
MakeKeyboardSelection(listItem);
}
}
#endregion
//-------------------------------------------------------------------
//
// Private Fields
//
//--------------------------------------------------------------------
#region Private Fields
///
/// "Anchor" of the selection. In extended selection, it is the pivot/anchor of the extended selection.
///
internal object AnchorItem
{
get
{
return GetWeakReferenceTarget(ref _anchorItem);
}
set
{
_anchorItem = new WeakReference(value);
}
}
///
/// Last item to be acted upon -- and the element that has focus while selection is happening.
/// AnchorItem != null implies LastActionItem != null.
///
internal ListBoxItem LastActionItem
{
get
{
return GetWeakReferenceTarget(ref _lastActionItem) as ListBoxItem;
}
set
{
_lastActionItem = new WeakReference(value);
}
}
private WeakReference _anchorItem;
private WeakReference _lastActionItem;
private DispatcherTimer _autoScrollTimer;
private static RoutedUICommand SelectAllCommand =
new RoutedUICommand(SR.Get(SRID.ListBoxSelectAllText), "SelectAll", typeof(ListBox));
#endregion
#region DTypeThemeStyleKey
// Returns the DependencyObjectType for the registered ThemeStyleKey's default
// value. Controls will override this method to return approriate types.
internal override DependencyObjectType DTypeThemeStyleKey
{
get { return _dType; }
}
private static DependencyObjectType _dType;
#endregion DTypeThemeStyleKey
}
///
/// The selection behavior for the ListBox.
///
public enum SelectionMode
{
///
/// Only one item can be selected at a time.
///
Single,
///
/// Items can be toggled selected.
///
Multiple,
///
/// Items can be selected in groups using the SHIFT and mouse or arrow keys.
///
Extended
// NOTE: if you add or remove any values in this enum, be sure to update ListBox.IsValidSelectionMode()
}
}
// 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 MS.Internal;
using MS.Utility;
using System.Collections;
using System.ComponentModel;
using System.Diagnostics;
using System.Windows.Threading;
using System.Windows.Media;
using System.Windows.Controls.Primitives;
using System.Windows.Input;
using System.Windows.Shapes;
using System.Windows.Data;
using System.Windows.Automation.Peers;
using System;
using MS.Internal.Commands; // CommandHelpers
using MS.Internal.KnownBoxes;
namespace System.Windows.Controls
{
///
/// Control that implements a list of selectable items.
///
[Localizability(LocalizationCategory.ListBox)]
[StyleTypedProperty(Property = "ItemContainerStyle", StyleTargetType = typeof(ListBoxItem))]
public class ListBox : Selector
{
//-------------------------------------------------------------------
//
// Constructors
//
//-------------------------------------------------------------------
#region Constructors
///
/// Default DependencyObject constructor
///
///
/// Automatic determination of current Dispatcher. Use alternative constructor
/// that accepts a Dispatcher for best performance.
///
public ListBox() : base()
{
Initialize();
}
// common code for all constructors
private void Initialize()
{
SelectionMode mode = (SelectionMode) SelectionModeProperty.GetDefaultValue(DependencyObjectType);
ValidateSelectionMode(mode);
}
static ListBox()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(typeof(ListBox)));
_dType = DependencyObjectType.FromSystemTypeInternal(typeof(ListBox));
IsTabStopProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(BooleanBoxes.FalseBox));
KeyboardNavigation.DirectionalNavigationProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(KeyboardNavigationMode.Contained));
KeyboardNavigation.TabNavigationProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(KeyboardNavigationMode.Once));
IsTextSearchEnabledProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(BooleanBoxes.TrueBox));
ItemsPanelTemplate template = new ItemsPanelTemplate(new FrameworkElementFactory(typeof(VirtualizingStackPanel)));
template.Seal();
ItemsPanelProperty.OverrideMetadata(typeof(ListBox), new FrameworkPropertyMetadata(template));
// Need handled events too here because any mouse up should release our mouse capture
EventManager.RegisterClassHandler(typeof(ListBox), Mouse.MouseUpEvent, new MouseButtonEventHandler(OnMouseButtonUp), true);
EventManager.RegisterClassHandler(typeof(ListBox), Keyboard.GotKeyboardFocusEvent, new KeyboardFocusChangedEventHandler(OnGotKeyboardFocus));
CommandHelpers.RegisterCommandHandler(typeof(ListBox), ListBox.SelectAllCommand, new ExecutedRoutedEventHandler(OnSelectAll), new CanExecuteRoutedEventHandler(OnQueryStatusSelectAll), KeyGesture.CreateFromResourceStrings(SR.Get(SRID.ListBoxSelectAllKey), SR.Get(SRID.ListBoxSelectAllKeyDisplayString)));
}
#endregion
//--------------------------------------------------------------------
//
// Public Methods
//
//-------------------------------------------------------------------
#region Public Methods
///
/// Select all the items
///
public void SelectAll()
{
if (CanSelectMultiple)
{
SelectAllImpl();
}
else
{
throw new NotSupportedException(SR.Get(SRID.ListBoxSelectAllSelectionMode));
}
}
///
/// Clears all of the selected items.
///
public void UnselectAll()
{
UnselectAllImpl();
}
///
/// Causes the object to scroll into view. If it is not visible, it is aligned either at the top or bottom of the viewport.
///
///
public void ScrollIntoView(object item)
{
if (ItemContainerGenerator.Status == GeneratorStatus.ContainersGenerated)
{
OnBringItemIntoView(item);
}
else
{
// The items aren't generated, try at a later time
Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new DispatcherOperationCallback(OnBringItemIntoView), item);
}
}
private object OnBringItemIntoView(object arg)
{
FrameworkElement element = ItemContainerGenerator.ContainerFromItem(arg) as FrameworkElement;
if (element != null)
{
element.BringIntoView();
}
else if (!IsGrouping && Items.Contains(arg))
{
// We might be virtualized, try to de-virtualize the item.
// Note: There is opportunity here to make a public OM.
VirtualizingPanel itemsHost = ItemsHost as VirtualizingPanel;
if (itemsHost != null)
{
itemsHost.BringIndexIntoView(Items.IndexOf(arg));
}
}
return null;
}
#endregion
//--------------------------------------------------------------------
//
// Public Properties
//
//--------------------------------------------------------------------
#region Public Properties
///
/// SelectionMode DependencyProperty
///
public static readonly DependencyProperty SelectionModeProperty =
DependencyProperty.Register(
"SelectionMode",
typeof(SelectionMode),
typeof(ListBox),
new FrameworkPropertyMetadata(
SelectionMode.Single,
new PropertyChangedCallback(OnSelectionModeChanged)),
new ValidateValueCallback(IsValidSelectionMode));
///
/// Indicates the selection behavior for the ListBox.
///
public SelectionMode SelectionMode
{
get { return (SelectionMode) GetValue(SelectionModeProperty); }
set { SetValue(SelectionModeProperty, value); }
}
private static void OnSelectionModeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ListBox listBox = (ListBox)d;
listBox.ValidateSelectionMode(listBox.SelectionMode);
}
private static object OnGetSelectionMode(DependencyObject d)
{
return ((ListBox)d).SelectionMode;
}
private static bool IsValidSelectionMode(object o)
{
SelectionMode value = (SelectionMode)o;
return value == SelectionMode.Single
|| value == SelectionMode.Multiple
|| value == SelectionMode.Extended;
}
private void ValidateSelectionMode(SelectionMode mode)
{
CanSelectMultiple = (mode != SelectionMode.Single);
}
///
/// A read-only IList containing the currently selected items
///
public static readonly DependencyProperty SelectedItemsProperty = Selector.SelectedItemsImplProperty;
///
/// The currently selected items.
///
[Bindable(true), Category("Appearance"), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
public IList SelectedItems
{
get
{
return SelectedItemsImpl;
}
}
#endregion
//-------------------------------------------------------------------
//
// Protected Methods
//
//--------------------------------------------------------------------
#region Protected Methods
///
/// Creates AutomationPeer ( )
///
protected override System.Windows.Automation.Peers.AutomationPeer OnCreateAutomationPeer()
{
return new System.Windows.Automation.Peers.ListBoxAutomationPeer(this);
}
///
/// Select multiple items.
///
/// Collection of items to be selected.
/// true if all items have been selected.
protected bool SetSelectedItems(IEnumerable selectedItems)
{
return SetSelectedItemsImpl(selectedItems);
}
///
/// Prepare the element to display the item. This may involve
/// applying styles, setting bindings, etc.
///
protected override void PrepareContainerForItemOverride(DependencyObject element, object item)
{
base.PrepareContainerForItemOverride(element, item);
if (item is Separator)
Separator.PrepareContainer(element as Control);
}
///
/// A virtual function that is called when the selection is changed. Default behavior
/// is to raise a SelectionChangedEvent
///
/// The inputs for this event. Can be raised (default behavior) or processed
/// in some other way.
protected override void OnSelectionChanged(SelectionChangedEventArgs e)
{
base.OnSelectionChanged(e);
// In a single selection mode we want to move anchor to the selected element
if (SelectionMode == SelectionMode.Single && SelectedItem != null)
{
ListBoxItem listItem = SelectedItem as ListBoxItem;
if (listItem == null)
listItem = ItemContainerGenerator.ContainerFromItem(SelectedItem) as ListBoxItem;
if (listItem != null)
UpdateAnchorAndActionItem(listItem);
}
if ( AutomationPeer.ListenerExists(AutomationEvents.SelectionPatternOnInvalidated)
|| AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementSelected)
|| AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementAddedToSelection)
|| AutomationPeer.ListenerExists(AutomationEvents.SelectionItemPatternOnElementRemovedFromSelection) )
{
ListBoxAutomationPeer peer = UIElementAutomationPeer.CreatePeerForElement(this) as ListBoxAutomationPeer;
if (peer != null)
peer.RaiseSelectionEvents(e);
}
}
///
/// This is the method that responds to the KeyDown event.
///
/// Event Arguments
protected override void OnKeyDown(KeyEventArgs e)
{
bool handled = true;
Key key = e.Key;
switch (key)
{
case Key.Divide:
case Key.Oem2:
// Ctrl-Fowardslash = Select All
if (((Keyboard.Modifiers & ModifierKeys.Control) == (ModifierKeys.Control)) && (SelectionMode == SelectionMode.Extended))
{
SelectAll();
}
else
{
handled = false;
}
break;
case Key.Oem5:
// Ctrl-Backslash = Select the item with focus.
if (((Keyboard.Modifiers & ModifierKeys.Control) == (ModifierKeys.Control)) && (SelectionMode == SelectionMode.Extended))
{
ListBoxItem focusedItemUI = ItemContainerGenerator.ContainerFromItem(FocusedItem) as ListBoxItem;
if (focusedItemUI != null)
{
MakeSingleSelection(focusedItemUI);
}
}
else
{
handled = false;
}
break;
case Key.Up:
case Key.Left:
case Key.Down:
case Key.Right:
{
KeyboardNavigation.ShowFocusVisual();
// Depend on logical orientation we decide to move focus or just scroll
// shouldScroll also detects if we can scroll more in this direction
bool shouldScroll = ScrollHost != null;
if (shouldScroll)
{
shouldScroll =
((key == Key.Down && IsLogicalHorizontal && DoubleUtil.GreaterThan(ScrollHost.ScrollableHeight, ScrollHost.VerticalOffset))) ||
((key == Key.Up && IsLogicalHorizontal && DoubleUtil.GreaterThan(ScrollHost.VerticalOffset, 0d))) ||
((key == Key.Right&& IsLogicalVertical && DoubleUtil.GreaterThan(ScrollHost.ScrollableWidth, ScrollHost.HorizontalOffset))) ||
((key == Key.Left && IsLogicalVertical && DoubleUtil.GreaterThan(ScrollHost.HorizontalOffset, 0d)));
}
if (shouldScroll)
{
ScrollHost.ScrollInDirection(e);
}
else
{
ListBoxItem listBoxItem = e.OriginalSource as ListBoxItem;
// Handle arrow keys only if the event source is ListBoxItem or ListBox itself
if (listBoxItem != null && ItemsControlFromItemContainer(listBoxItem) == this)
{
// Navigate focus from current ListBoxItem
if (!listBoxItem.MoveFocus(new TraversalRequest(KeyboardNavigation.KeyToTraversalDirection(key))))
handled = false;
}
else
{
if (e.OriginalSource == this)
NavigateToStart(ItemNavigateArgs.Empty);
else
handled = false;
}
}
}
break;
case Key.Home:
NavigateToStart(new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
break;
case Key.End:
NavigateToEnd(new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
break;
case Key.Space:
case Key.Enter:
{
if (e.Key == Key.Enter && (bool)GetValue(KeyboardNavigation.AcceptsReturnProperty) == false)
{
handled = false;
break;
}
// If the event came from a ListBoxItem that's a child of ours, then look at it.
ListBoxItem source = e.OriginalSource as ListBoxItem;
// If ALT is down & Ctrl is up, then we shouldn't handle this. (system menu)
if ((Keyboard.Modifiers & (ModifierKeys.Control|ModifierKeys.Alt)) == ModifierKeys.Alt)
{
handled = false;
break;
}
// If the user hits just "space" while text searching, do not handle the event
// Note: Space cannot be the first character in a string sent to ITS.
if (IsTextSearchEnabled && Keyboard.Modifiers == ModifierKeys.None)
{
TextSearch instance = TextSearch.EnsureInstance(this);
// If TextSearch enabled and Prefix is not empty
// then let this SPACE go so ITS can process it.
if (instance != null && (instance.GetCurrentPrefix() != String.Empty))
{
handled = false;
break;
}
}
if (source != null && ItemsControlFromItemContainer(source) == this)
{
switch (SelectionMode)
{
case SelectionMode.Single:
if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
MakeToggleSelection(source);
}
else
{
MakeSingleSelection(source);
}
break;
case SelectionMode.Multiple:
MakeToggleSelection(source);
break;
case SelectionMode.Extended:
if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == ModifierKeys.Control)
{
// Only CONTROL
MakeToggleSelection(source);
}
else if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == ModifierKeys.Shift)
{
// Only SHIFT
MakeAnchorSelection(source, true /* clearCurrent */);
}
else if ((Keyboard.Modifiers & ModifierKeys.Shift) == 0)
{
MakeSingleSelection(source);
}
else
{
handled = false;
}
break;
}
}
else
{
handled = false;
}
}
break;
case Key.PageUp:
NavigateByPage(FocusNavigationDirection.Up, new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
break;
case Key.PageDown:
NavigateByPage(FocusNavigationDirection.Down, new ItemNavigateArgs(e.Device, Keyboard.Modifiers));
break;
default:
handled = false;
break;
}
if (handled)
{
e.Handled = true;
}
else
{
base.OnKeyDown(e);
}
}
///
/// An event reporting a mouse move.
///
protected override void OnMouseMove(MouseEventArgs e)
{
// If we get a mouse move and we have capture, then the mouse was
// outside the ListBox. We should autoscroll.
if (e.OriginalSource == this && Mouse.Captured == this)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
DoAutoScroll();
}
else
{
// We missed the mouse up, release capture
ReleaseMouseCapture();
ResetLastMousePosition();
}
}
base.OnMouseMove(e);
}
private static void OnMouseButtonUp(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton == MouseButton.Left)
{
ListBox listBox = (ListBox)sender;
listBox.ReleaseMouseCapture();
listBox.ResetLastMousePosition();
}
}
private static void OnGotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
ListBox listbox = (ListBox)sender;
// Focus drives the selection when keyboardnavigation is used
if (!KeyboardNavigation.IsKeyboardMostRecentInputDevice())
return;
// Only in case focus moves from one ListBoxItem to another we want the selection to follow focus
ListBoxItem newListBoxItem = e.NewFocus as ListBoxItem;
if (newListBoxItem != null && ItemsControlFromItemContainer(newListBoxItem) == listbox)
{
DependencyObject oldFocus = e.OldFocus as DependencyObject;
Visual visualOldFocus = oldFocus as Visual;
if (visualOldFocus == null)
{
ContentElement ce = oldFocus as ContentElement;
if (ce != null)
visualOldFocus = KeyboardNavigation.GetParentUIElementFromContentElement(ce);
}
if ((visualOldFocus != null && listbox.IsAncestorOf(visualOldFocus))
|| oldFocus == listbox)
{
listbox.LastActionItem = newListBoxItem;
listbox.MakeKeyboardSelection(newListBoxItem);
}
}
}
///
/// Called when IsMouseCaptured changes on this element.
///
///
protected override void OnIsMouseCapturedChanged(DependencyPropertyChangedEventArgs e)
{
// When we take capture, we should start a timer to call
// us back and do auto scrolling behavior.
if (IsMouseCaptured)
{
Debug.Assert(_autoScrollTimer == null, "IsMouseCaptured went from true to true");
if (_autoScrollTimer == null)
{
_autoScrollTimer = new DispatcherTimer(DispatcherPriority.SystemIdle);
_autoScrollTimer.Interval = AutoScrollTimeout;
_autoScrollTimer.Tick += new EventHandler(OnAutoScrollTimeout);
_autoScrollTimer.Start();
}
}
else
{
if (_autoScrollTimer != null)
{
_autoScrollTimer.Stop();
_autoScrollTimer = null;
}
}
base.OnIsMouseCapturedChanged(e);
}
///
/// Return true if the item is (or is eligible to be) its own ItemContainer
///
protected override bool IsItemItsOwnContainerOverride(object item)
{
return (item is ListBoxItem);
}
/// Create or identify the element used to display the given item.
protected override DependencyObject GetContainerForItemOverride()
{
return new ListBoxItem();
}
///
/// If control has a scrollviewer in its style and has a custom keyboard scrolling behavior when HandlesScrolling should return true.
/// Then ScrollViewer will not handle keyboard input and leave it up to the control.
///
protected internal override bool HandlesScrolling
{
get
{
return true;
}
}
#endregion
//-------------------------------------------------------------------
//
// Private Methods
//
//-------------------------------------------------------------------
#region Private Methods
private static void OnQueryStatusSelectAll(object target, CanExecuteRoutedEventArgs args)
{
ListBox listBox = target as ListBox;
if (listBox.SelectionMode == SelectionMode.Extended)
{
args.CanExecute = true;
}
}
private static void OnSelectAll(object target, ExecutedRoutedEventArgs args)
{
ListBox listBox = target as ListBox;
if (listBox.SelectionMode == SelectionMode.Extended)
{
listBox.SelectAll();
}
}
internal void NotifyListItemClicked(ListBoxItem item, MouseButton mouseButton)
{
// When a ListBoxItem is left clicked, we should take capture
// so we can auto scroll through the list.
if (mouseButton == MouseButton.Left && Mouse.Captured != this)
{
Mouse.Capture(this, CaptureMode.SubTree);
SetInitialMousePosition(); // Start tracking mouse movement
}
switch (SelectionMode)
{
case SelectionMode.Single:
{
if (!item.IsSelected)
{
item.IsSelected = true;
}
else if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
item.IsSelected = false;
}
UpdateAnchorAndActionItem(item);
}
break;
case SelectionMode.Multiple:
MakeToggleSelection(item);
break;
case SelectionMode.Extended:
// Extended selection works only with Left mouse button
if (mouseButton == MouseButton.Left)
{
if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == (ModifierKeys.Control | ModifierKeys.Shift))
{
MakeAnchorSelection(item, false);
}
else if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control)
{
MakeToggleSelection(item);
}
else if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
{
MakeAnchorSelection(item, true);
}
else
{
MakeSingleSelection(item);
}
}
else if (mouseButton == MouseButton.Right) // Right mouse button
{
// Shift or Control combination should not trigger any action
// If only Right mouse button is pressed we should move the anchor
// and select the item only if element under the mouse is not selected
if ((Keyboard.Modifiers & (ModifierKeys.Control | ModifierKeys.Shift)) == 0)
{
if (item.IsSelected)
UpdateAnchorAndActionItem(item);
else
MakeSingleSelection(item);
}
}
break;
}
}
internal void NotifyListItemMouseDragged(ListBoxItem listItem)
{
if ((Mouse.Captured == this) && DidMouseMove())
{
NavigateToItem(ItemContainerGenerator.ItemFromContainer(listItem), new ItemNavigateArgs(Mouse.PrimaryDevice, Keyboard.Modifiers));
}
}
private void UpdateAnchorAndActionItem(ListBoxItem listItem)
{
object item = ItemContainerGenerator.ItemFromContainer(listItem);
if (item == DependencyProperty.UnsetValue)
{
AnchorItem = null;
LastActionItem = null;
}
else
{
AnchorItem = item;
LastActionItem = listItem;
}
KeyboardNavigation.SetTabOnceActiveElement(this, listItem);
}
private void MakeSingleSelection(ListBoxItem listItem)
{
if (ItemsControlFromItemContainer(listItem) == this)
{
object item = ItemContainerGenerator.ItemFromContainer(listItem);
SelectionChange.SelectJustThisItem(item, true /* assumeInItemsCollection */);
listItem.Focus();
UpdateAnchorAndActionItem(listItem);
}
}
private void MakeToggleSelection(ListBoxItem item)
{
bool select = !item.IsSelected;
item.IsSelected = select;
UpdateAnchorAndActionItem(item);
}
private void MakeAnchorSelection(ListBoxItem actionItem, bool clearCurrent)
{
if (AnchorItem == null)
{
if (_selectedItems.Count > 0)
{
// If we haven't set the anchor, then just use the last selected item
AnchorItem = _selectedItems[_selectedItems.Count - 1];
}
else
{
// There was nothing selected, so take the first child element
AnchorItem = Items[0];
}
if (AnchorItem == null)
{
// Can't do anything
return;
}
}
// Find the indexes of the elements
int start, end;
start = ElementIndex(actionItem);
end = Items.IndexOf(AnchorItem);
// Ensure start is before end
if (start > end)
{
int index = start;
start = end;
end = index;
}
bool beganSelectionChange = false;
if (!SelectionChange.IsActive)
{
beganSelectionChange = true;
SelectionChange.Begin();
}
try
{
if (clearCurrent)
{
// Unselect items not within the selection range
for (int index = 0; index < _selectedItems.Count; index++)
{
object item = _selectedItems[index];
int itemIndex = Items.IndexOf(item);
if ((itemIndex < start) || (end < itemIndex))
{
SelectionChange.Unselect(item);
}
}
}
// Select the children in the selection range
IEnumerator enumerator = ((IEnumerable)Items).GetEnumerator();
for (int index = 0; index <= end; index++)
{
enumerator.MoveNext();
if (index >= start)
{
SelectionChange.Select(enumerator.Current, true /* assumeInItemsCollection */);
}
}
}
finally
{
if (beganSelectionChange)
{
SelectionChange.End();
}
}
LastActionItem = actionItem;
}
private void MakeKeyboardSelection(ListBoxItem item)
{
if (item == null)
{
return;
}
switch (SelectionMode)
{
case SelectionMode.Single:
// Navigating when control is down shouldn't select the item
if ((Keyboard.Modifiers & ModifierKeys.Control) == 0)
{
MakeSingleSelection(item);
}
break;
case SelectionMode.Multiple:
UpdateAnchorAndActionItem(item);
break;
case SelectionMode.Extended:
if ((Keyboard.Modifiers & ModifierKeys.Shift) == ModifierKeys.Shift)
{
bool clearCurrentSelection = (Keyboard.Modifiers & ModifierKeys.Control) == 0;
MakeAnchorSelection(item, clearCurrentSelection);
}
else if ((Keyboard.Modifiers & ModifierKeys.Control) == 0)
{
MakeSingleSelection(item);
}
break;
}
}
private int ElementIndex(ListBoxItem listItem)
{
return ItemContainerGenerator.IndexFromContainer(listItem);
}
private ListBoxItem ElementAt(int index)
{
return ItemContainerGenerator.ContainerFromIndex(index) as ListBoxItem;
}
private object GetWeakReferenceTarget(ref WeakReference weakReference)
{
if (weakReference != null)
{
return weakReference.Target;
}
return null;
}
private void OnAutoScrollTimeout(object sender, EventArgs e)
{
if (Mouse.LeftButton == MouseButtonState.Pressed)
{
DoAutoScroll();
}
}
///
/// Called when an item is being focused
///
internal override void FocusItem(object item, ItemNavigateArgs itemNavigateArgs)
{
// Base will actually focus the item
base.FocusItem(item, itemNavigateArgs);
ListBoxItem listItem = ItemContainerGenerator.ContainerFromItem(item) as ListBoxItem;
if (listItem != null)
{
LastActionItem = listItem;
//
MakeKeyboardSelection(listItem);
}
}
#endregion
//-------------------------------------------------------------------
//
// Private Fields
//
//--------------------------------------------------------------------
#region Private Fields
///
/// "Anchor" of the selection. In extended selection, it is the pivot/anchor of the extended selection.
///
internal object AnchorItem
{
get
{
return GetWeakReferenceTarget(ref _anchorItem);
}
set
{
_anchorItem = new WeakReference(value);
}
}
///
/// Last item to be acted upon -- and the element that has focus while selection is happening.
/// AnchorItem != null implies LastActionItem != null.
///
internal ListBoxItem LastActionItem
{
get
{
return GetWeakReferenceTarget(ref _lastActionItem) as ListBoxItem;
}
set
{
_lastActionItem = new WeakReference(value);
}
}
private WeakReference _anchorItem;
private WeakReference _lastActionItem;
private DispatcherTimer _autoScrollTimer;
private static RoutedUICommand SelectAllCommand =
new RoutedUICommand(SR.Get(SRID.ListBoxSelectAllText), "SelectAll", typeof(ListBox));
#endregion
#region DTypeThemeStyleKey
// Returns the DependencyObjectType for the registered ThemeStyleKey's default
// value. Controls will override this method to return approriate types.
internal override DependencyObjectType DTypeThemeStyleKey
{
get { return _dType; }
}
private static DependencyObjectType _dType;
#endregion DTypeThemeStyleKey
}
///
/// The selection behavior for the ListBox.
///
public enum SelectionMode
{
///
/// Only one item can be selected at a time.
///
Single,
///
/// Items can be toggled selected.
///
Multiple,
///
/// Items can be selected in groups using the SHIFT and mouse or arrow keys.
///
Extended
// NOTE: if you add or remove any values in this enum, be sure to update ListBox.IsValidSelectionMode()
}
}
// 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
- HMACSHA1.cs
- FocusChangedEventArgs.cs
- VectorCollectionValueSerializer.cs
- StackSpiller.Temps.cs
- Html32TextWriter.cs
- DaylightTime.cs
- Registration.cs
- LiteralDesigner.cs
- MetabaseSettingsIis7.cs
- BlurEffect.cs
- HierarchicalDataSourceControl.cs
- RightsManagementErrorHandler.cs
- ClusterUtils.cs
- SizeValueSerializer.cs
- QueryPageSettingsEventArgs.cs
- Win32Interop.cs
- httpstaticobjectscollection.cs
- SafeFindHandle.cs
- DesignerSerializationOptionsAttribute.cs
- BamlBinaryReader.cs
- NGCSerializationManagerAsync.cs
- GeneratedCodeAttribute.cs
- GlyphRun.cs
- FlatButtonAppearance.cs
- DrawListViewColumnHeaderEventArgs.cs
- StringPropertyBuilder.cs
- SamlAttribute.cs
- ToolStripHighContrastRenderer.cs
- TemplateField.cs
- DbConnectionPool.cs
- HandlerBase.cs
- X509Certificate2.cs
- DbTransaction.cs
- XmlValueConverter.cs
- DataBindingCollection.cs
- SoapServerMessage.cs
- URI.cs
- InvocationExpression.cs
- SetterTriggerConditionValueConverter.cs
- Shape.cs
- WebPartManagerInternals.cs
- ApplicationId.cs
- DigitShape.cs
- DesignerDataSchemaClass.cs
- ServiceNotStartedException.cs
- DbProviderFactoriesConfigurationHandler.cs
- BrushMappingModeValidation.cs
- XmlSchemaValidationException.cs
- RouteData.cs
- OperationResponse.cs
- InvokeDelegate.cs
- TypeResolver.cs
- DbProviderManifest.cs
- Logging.cs
- Style.cs
- SignatureToken.cs
- EnumType.cs
- FieldInfo.cs
- TextTrailingWordEllipsis.cs
- future.cs
- Accessible.cs
- IDispatchConstantAttribute.cs
- BlockExpression.cs
- DefinitionUpdate.cs
- AsyncInvokeOperation.cs
- ExpressionTextBox.xaml.cs
- BindingContext.cs
- OutputWindow.cs
- BitmapEffect.cs
- XmlnsCompatibleWithAttribute.cs
- InheritanceRules.cs
- CodeDirectoryCompiler.cs
- XmlSerializationReader.cs
- ButtonBaseAdapter.cs
- AnonymousIdentificationModule.cs
- IDispatchConstantAttribute.cs
- XomlCompiler.cs
- FieldDescriptor.cs
- DataTableMappingCollection.cs
- CompositeCollection.cs
- ThreadStartException.cs
- ImpersonationOption.cs
- WebServiceClientProxyGenerator.cs
- LongPath.cs
- PublisherIdentityPermission.cs
- ConnectionsZone.cs
- FixedBufferAttribute.cs
- _CookieModule.cs
- MachineSettingsSection.cs
- XamlStyleSerializer.cs
- BuildManagerHost.cs
- Thread.cs
- TypeGenericEnumerableViewSchema.cs
- XmlRawWriter.cs
- COM2ColorConverter.cs
- SerializationObjectManager.cs
- ValidationRuleCollection.cs
- RC2.cs
- SafeLibraryHandle.cs
- BeginCreateSecurityTokenRequest.cs