ListBox.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / wpf / src / Framework / System / Windows / Controls / ListBox.cs / 1305600 / 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);
            }
        } 

        #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))))
                                { 
                                    KeyboardNavigationMode mode = KeyboardNavigation.GetDirectionalNavigation(this);
                                    if (mode != KeyboardNavigationMode.Contained &&
                                        mode != KeyboardNavigationMode.Cycle)
                                    { 
                                        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.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.TrueBox);
                        } 
                        else if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) 
                        {
                            item.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.FalseBox); 
                        }

                        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.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.Box(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);
            }
        } 

        #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))))
                                { 
                                    KeyboardNavigationMode mode = KeyboardNavigation.GetDirectionalNavigation(this);
                                    if (mode != KeyboardNavigationMode.Contained &&
                                        mode != KeyboardNavigationMode.Cycle)
                                    { 
                                        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.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.TrueBox);
                        } 
                        else if ((Keyboard.Modifiers & ModifierKeys.Control) == ModifierKeys.Control) 
                        {
                            item.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.FalseBox); 
                        }

                        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.SetCurrentValueInternal(IsSelectedProperty, BooleanBoxes.Box(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

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