ListBox.cs source code in C# .NET

Source code for the .NET framework in C#

                        

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

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