X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fclass%2FManaged.Windows.Forms%2FSystem.Windows.Forms%2FListView.cs;h=c1b7d791f8d2974c14d91a11622fb822eee0dafa;hb=2f9c820c7ee1063d9fabcb2410b57843c17cb926;hp=eb40f98338d8abee32e8c1264cbcfb5a474ec6a6;hpb=9e96be5250df54ea3a2ca5c722ecf2eb996a29d9;p=mono.git diff --git a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListView.cs b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListView.cs index eb40f98338d..c1b7d791f8d 100644 --- a/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListView.cs +++ b/mcs/class/Managed.Windows.Forms/System.Windows.Forms/ListView.cs @@ -37,20 +37,16 @@ using System.ComponentModel.Design; using System.Drawing; using System.Runtime.InteropServices; using System.Globalization; -#if NET_2_0 using System.Collections.Generic; -#endif namespace System.Windows.Forms { [DefaultEvent ("SelectedIndexChanged")] [DefaultProperty ("Items")] [Designer ("System.Windows.Forms.Design.ListViewDesigner, " + Consts.AssemblySystem_Design, "System.ComponentModel.Design.IDesigner")] -#if NET_2_0 [ClassInterface (ClassInterfaceType.AutoDispatch)] [ComVisible (true)] [Docking (DockingBehavior.Ask)] -#endif public class ListView : Control { private ItemActivation activation = ItemActivation.Standard; @@ -69,11 +65,9 @@ namespace System.Windows.Forms private bool hover_selection; private IComparer item_sorter; private readonly ListViewItemCollection items; -#if NET_2_0 private readonly ListViewGroupCollection groups; private bool owner_draw; private bool show_groups = true; -#endif private bool label_edit; private bool label_wrap = true; private bool multiselect = true; @@ -87,7 +81,7 @@ namespace System.Windows.Forms private View view = View.LargeIcon; private int layout_wd; // We might draw more than our client area private int layout_ht; // therefore we need to have these two. - HeaderControl header_control; + internal HeaderControl header_control; internal ItemControl item_control; internal ScrollBar h_scroll; // used for scrolling horizontally internal ScrollBar v_scroll; // used for scrolling vertically @@ -103,7 +97,6 @@ namespace System.Windows.Forms private Size item_size; // used for caching item size private int custom_column_width; // used when using Columns with SmallIcon/List views private int hot_item_index = -1; -#if NET_2_0 private bool hot_tracking; private ListViewInsertionMark insertion_mark; private bool show_item_tooltips; @@ -112,7 +105,9 @@ namespace System.Windows.Forms private bool virtual_mode; private int virtual_list_size; private bool right_to_left_layout; -#endif + // selection is available after the first time the handle is created, *even* if later + // the handle is either recreated or destroyed - so keep this info around. + private bool is_selection_available; // internal variables internal ImageList large_image_list; @@ -127,7 +122,6 @@ namespace System.Windows.Forms static object ItemCheckEvent = new object (); static object ItemDragEvent = new object (); static object SelectedIndexChangedEvent = new object (); -#if NET_2_0 static object DrawColumnHeaderEvent = new object(); static object DrawItemEvent = new object(); static object DrawSubItemEvent = new object(); @@ -139,30 +133,19 @@ namespace System.Windows.Forms static object RightToLeftLayoutChangedEvent = new object (); static object SearchForVirtualItemEvent = new object (); static object VirtualItemsSelectionRangeChangedEvent = new object (); -#endif public event LabelEditEventHandler AfterLabelEdit { add { Events.AddHandler (AfterLabelEditEvent, value); } remove { Events.RemoveHandler (AfterLabelEditEvent, value); } } -#if !NET_2_0 - [Browsable (false)] - [EditorBrowsable (EditorBrowsableState.Never)] - public new event EventHandler BackgroundImageChanged { - add { base.BackgroundImageChanged += value; } - remove { base.BackgroundImageChanged -= value; } - } -#endif -#if NET_2_0 [Browsable (false)] [EditorBrowsable (EditorBrowsableState.Never)] public new event EventHandler BackgroundImageLayoutChanged { add { base.BackgroundImageLayoutChanged += value; } remove { base.BackgroundImageLayoutChanged -= value; } } -#endif public event LabelEditEventHandler BeforeLabelEdit { add { Events.AddHandler (BeforeLabelEditEvent, value); } @@ -174,7 +157,6 @@ namespace System.Windows.Forms remove { Events.RemoveHandler (ColumnClickEvent, value); } } -#if NET_2_0 public event DrawListViewColumnHeaderEventHandler DrawColumnHeader { add { Events.AddHandler(DrawColumnHeaderEvent, value); } remove { Events.RemoveHandler(DrawColumnHeaderEvent, value); } @@ -189,7 +171,6 @@ namespace System.Windows.Forms add { Events.AddHandler(DrawSubItemEvent, value); } remove { Events.RemoveHandler(DrawSubItemEvent, value); } } -#endif public event EventHandler ItemActivate { add { Events.AddHandler (ItemActivateEvent, value); } @@ -201,19 +182,16 @@ namespace System.Windows.Forms remove { Events.RemoveHandler (ItemCheckEvent, value); } } -#if NET_2_0 public event ItemCheckedEventHandler ItemChecked { add { Events.AddHandler (ItemCheckedEvent, value); } remove { Events.RemoveHandler (ItemCheckedEvent, value); } } -#endif public event ItemDragEventHandler ItemDrag { add { Events.AddHandler (ItemDragEvent, value); } remove { Events.RemoveHandler (ItemDragEvent, value); } } -#if NET_2_0 public event ListViewItemMouseHoverEventHandler ItemMouseHover { add { Events.AddHandler (ItemMouseHoverEvent, value); } remove { Events.RemoveHandler (ItemMouseHoverEvent, value); } @@ -230,7 +208,6 @@ namespace System.Windows.Forms add { base.PaddingChanged += value; } remove { base.PaddingChanged -= value; } } -#endif [Browsable (false)] [EditorBrowsable (EditorBrowsableState.Never)] @@ -251,7 +228,6 @@ namespace System.Windows.Forms remove { base.TextChanged -= value; } } -#if NET_2_0 public event CacheVirtualItemsEventHandler CacheVirtualItems { add { Events.AddHandler (CacheVirtualItemsEvent, value); } remove { Events.RemoveHandler (CacheVirtualItemsEvent, value); } @@ -276,7 +252,6 @@ namespace System.Windows.Forms add { Events.AddHandler (VirtualItemsSelectionRangeChangedEvent, value); } remove { Events.RemoveHandler (VirtualItemsSelectionRangeChangedEvent, value); } } -#endif #endregion // Events @@ -284,10 +259,9 @@ namespace System.Windows.Forms public ListView () { background_color = ThemeEngine.Current.ColorWindow; -#if NET_2_0 groups = new ListViewGroupCollection (this); -#endif items = new ListViewItemCollection (this); + items.Changed += new CollectionChangedHandler (OnItemsChanged); checked_indices = new CheckedIndexCollection (this); checked_items = new CheckedListViewItemCollection (this); columns = new ColumnHeaderCollection (this); @@ -297,11 +271,9 @@ namespace System.Windows.Forms items_location = new Point [16]; items_matrix_location = new ItemMatrixLocation [16]; reordered_items_indices = new int [16]; -#if NET_2_0 item_tooltip = new ToolTip (); item_tooltip.Active = false; insertion_mark = new ListViewInsertionMark (this); -#endif InternalBorderStyle = BorderStyle.Fixed3D; @@ -334,15 +306,12 @@ namespace System.Windows.Forms LostFocus += new EventHandler (FocusChanged); MouseWheel += new MouseEventHandler(ListView_MouseWheel); MouseEnter += new EventHandler (ListView_MouseEnter); + Invalidated += new InvalidateEventHandler (ListView_Invalidated); -#if NET_2_0 BackgroundImageTiled = false; -#endif this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick -#if NET_2_0 | ControlStyles.UseTextForAccessibility -#endif , false); } #endregion // Public Constructors @@ -386,6 +355,13 @@ namespace System.Windows.Forms } } + internal bool UsingGroups { + get { + return show_groups && groups.Count > 0 && view != View.List && + Application.VisualStylesEnabled; + } + } + internal override bool ScaleChildrenInternal { get { return false; } } @@ -396,6 +372,11 @@ namespace System.Windows.Forms } } + internal ColumnHeader EnteredColumnHeader { + get { + return header_control.EnteredColumnHeader; + } + } #endregion // Private Internal Properties #region Protected Properties @@ -406,7 +387,6 @@ namespace System.Windows.Forms protected override Size DefaultSize { get { return ThemeEngine.Current.ListViewDefaultSize; } } -#if NET_2_0 protected override bool DoubleBuffered { get { return base.DoubleBuffered; @@ -415,7 +395,6 @@ namespace System.Windows.Forms base.DoubleBuffered = value; } } -#endif #endregion // Protected Properties #region Public Instance Properties @@ -428,10 +407,8 @@ namespace System.Windows.Forms throw new InvalidEnumArgumentException (string.Format ("Enum argument value '{0}' is not valid for Activation", value)); } -#if NET_2_0 if (hot_tracking && value != ItemActivation.OneClick) throw new ArgumentException ("When HotTracking is on, activation must be ItemActivation.OneClick"); -#endif activation = value; } @@ -489,16 +466,6 @@ namespace System.Windows.Forms } } -#if !NET_2_0 - [Browsable (false)] - [EditorBrowsable (EditorBrowsableState.Never)] - public override Image BackgroundImage { - get { return base.BackgroundImage; } - set { base.BackgroundImage = value; } - } -#endif - -#if NET_2_0 [Browsable (false)] [EditorBrowsable (EditorBrowsableState.Never)] public override ImageLayout BackgroundImageLayout { @@ -523,7 +490,6 @@ namespace System.Windows.Forms item_control.BackgroundImageLayout = new_image_layout; } } -#endif [DefaultValue (BorderStyle.Fixed3D)] [DispId (-504)] @@ -537,15 +503,16 @@ namespace System.Windows.Forms get { return check_boxes; } set { if (check_boxes != value) { -#if NET_2_0 if (value && View == View.Tile) throw new NotSupportedException ("CheckBoxes are not" + " supported in Tile view. Choose a different" + " view or set CheckBoxes to false."); -#endif check_boxes = value; this.Redraw (true); + + //UIA Framework: Event used by ListView to set/unset Toggle Pattern + OnUIACheckBoxesChanged (); } } } @@ -562,9 +529,7 @@ namespace System.Windows.Forms get { return checked_items; } } -#if NET_2_0 [Editor ("System.Windows.Forms.Design.ColumnHeaderCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] -#endif [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] [Localizable (true)] [MergableProperty (false)] @@ -579,17 +544,15 @@ namespace System.Windows.Forms if (focused_item_index == -1) return null; - return items [focused_item_index]; + return GetItemAtDisplayIndex (focused_item_index); } -#if NET_2_0 set { if (value == null || value.ListView != this || !IsHandleCreated) return; - SetFocusedItem (value.Index); + SetFocusedItem (value.DisplayIndex); } -#endif } public override Color ForeColor { @@ -658,7 +621,6 @@ namespace System.Windows.Forms } } -#if NET_2_0 [DefaultValue (false)] public bool HotTracking { get { @@ -675,21 +637,17 @@ namespace System.Windows.Forms } } } -#endif [DefaultValue (false)] public bool HoverSelection { get { return hover_selection; } set { -#if NET_2_0 if (hot_tracking && value == false) throw new ArgumentException ("When HotTracking is on, hover selection must be true"); -#endif hover_selection = value; } } -#if NET_2_0 [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] [Browsable (false)] public ListViewInsertionMark InsertionMark { @@ -697,11 +655,8 @@ namespace System.Windows.Forms return insertion_mark; } } -#endif -#if NET_2_0 [Editor ("System.Windows.Forms.Design.ListViewItemCollectionEditor, " + Consts.AssemblySystem_Design, typeof (System.Drawing.Design.UITypeEditor))] -#endif [DesignerSerializationVisibility (DesignerSerializationVisibility.Content)] [Localizable (true)] [MergableProperty (false)] @@ -712,7 +667,15 @@ namespace System.Windows.Forms [DefaultValue (false)] public bool LabelEdit { get { return label_edit; } - set { label_edit = value; } + set { + if (value != label_edit) { + label_edit = value; + + // UIA Framework: Event used by Value Pattern in ListView.ListItem provider + OnUIALabelEditChanged (); + } + + } } [DefaultValue (true)] @@ -755,11 +718,17 @@ namespace System.Windows.Forms [DefaultValue (true)] public bool MultiSelect { get { return multiselect; } - set { multiselect = value; } + set { + if (value != multiselect) { + multiselect = value; + + // UIA Framework: Event used by Selection Pattern in ListView.ListItem provider + OnUIAMultiSelectChanged (); + } + } } -#if NET_2_0 [DefaultValue(false)] public bool OwnerDraw { get { return owner_draw; } @@ -793,7 +762,6 @@ namespace System.Windows.Forms } } } -#endif [DefaultValue (true)] public bool Scrollable { @@ -818,7 +786,6 @@ namespace System.Windows.Forms get { return selected_items; } } -#if NET_2_0 [DefaultValue(true)] public bool ShowGroups { get { return show_groups; } @@ -826,6 +793,9 @@ namespace System.Windows.Forms if (show_groups != value) { show_groups = value; Redraw(true); + + // UIA Framework: Used to update a11y Tree + OnUIAShowGroupsChanged (); } } } @@ -848,7 +818,6 @@ namespace System.Windows.Forms item_tooltip.Active = false; } } -#endif [DefaultValue (null)] public ImageList SmallImageList { @@ -873,39 +842,22 @@ namespace System.Windows.Forms sort_order = value; -#if NET_2_0 if (virtual_mode) // Sorting is not allowed in virtual mode return; -#endif if (value == SortOrder.None) { if (item_sorter != null) { // ListViewItemSorter should never be reset for SmallIcon // and LargeIcon view if (View != View.SmallIcon && View != View.LargeIcon) -#if NET_2_0 item_sorter = null; -#else - // in .NET 1.1, only internal IComparer would be - // set to null - if (item_sorter is ItemComparer) - item_sorter = null; -#endif } this.Redraw (false); } else { if (item_sorter == null) item_sorter = new ItemComparer (value); if (item_sorter is ItemComparer) { -#if NET_2_0 item_sorter = new ItemComparer (value); -#else - // in .NET 1.1, the sort order is not updated for - // SmallIcon and LargeIcon views if no custom IComparer - // is set - if (View != View.SmallIcon && View != View.LargeIcon) - item_sorter = new ItemComparer (value); -#endif } Sort (); } @@ -950,7 +902,6 @@ namespace System.Windows.Forms } } -#if NET_2_0 [Browsable (true)] public Size TileSize { get { @@ -961,19 +912,17 @@ namespace System.Windows.Forms throw new ArgumentOutOfRangeException ("value"); tile_size = value; - Redraw (true); + if (view == View.Tile) + Redraw (true); } } -#endif [Browsable (false)] [DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)] public ListViewItem TopItem { get { -#if NET_2_0 if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile) throw new InvalidOperationException ("Cannot get the top item in LargeIcon, SmallIcon or Tile view."); -#endif // there is no item if (this.items.Count == 0) return null; @@ -983,15 +932,15 @@ namespace System.Windows.Forms return this.items [0]; // do a hit test for the scrolled position else { + int header_offset = header_control.Height; for (int i = 0; i < items.Count; i++) { Point item_loc = GetItemLocation (i); - if (item_loc.X >= 0 && item_loc.Y >= 0) + if (item_loc.X >= 0 && item_loc.Y - header_offset >= 0) return items [i]; } return null; } } -#if NET_2_0 set { if (view == View.LargeIcon || view == View.SmallIcon || view == View.Tile) throw new InvalidOperationException ("Cannot set the top item in LargeIcon, SmallIcon or Tile view."); @@ -1000,12 +949,11 @@ namespace System.Windows.Forms if (value == null || value.ListView != this) return; - EnsureVisible (value.Index); + // Take advantage this property is only valid for Details view. + SetScrollValue (v_scroll, item_size.Height * value.Index); } -#endif } -#if NET_2_0 [EditorBrowsable (EditorBrowsableState.Advanced)] [DefaultValue (true)] [Browsable (false)] @@ -1017,7 +965,6 @@ namespace System.Windows.Forms set { } } -#endif [DefaultValue (View.LargeIcon)] public View View { @@ -1028,21 +975,25 @@ namespace System.Windows.Forms typeof (View)); if (view != value) { -#if NET_2_0 if (CheckBoxes && value == View.Tile) throw new NotSupportedException ("CheckBoxes are not" + " supported in Tile view. Choose a different" + " view or set CheckBoxes to false."); -#endif + if (VirtualMode && value == View.Tile) + throw new NotSupportedException ("VirtualMode is" + + " not supported in Tile view. Choose a different" + + " view or set ViewMode to false."); h_scroll.Value = v_scroll.Value = 0; view = value; Redraw (true); + + // UIA Framework: Event used to update UIA Tree. + OnUIAViewChanged (); } } } -#if NET_2_0 [DefaultValue (false)] [RefreshProperties (RefreshProperties.Repaint)] public bool VirtualMode { @@ -1055,6 +1006,10 @@ namespace System.Windows.Forms if (!virtual_mode && items.Count > 0) throw new InvalidOperationException (); + if (value && view == View.Tile) + throw new NotSupportedException ("VirtualMode is" + + " not supported in Tile view. Choose a different" + + " view or set ViewMode to false."); virtual_mode = value; Redraw (true); @@ -1081,7 +1036,6 @@ namespace System.Windows.Forms } } } -#endif #endregion // Public Instance Properties #region Internal Methods Properties @@ -1096,6 +1050,27 @@ namespace System.Windows.Forms return 0; Size item_size = ItemSize; + // In virtual mode we always have fixed positions, and we can infer the positon easily + if (virtual_mode) { + int first = 0; + switch (view) { + case View.Details: + first = v_marker / item_size.Height; + break; + case View.LargeIcon: + case View.SmallIcon: + first = (v_marker / (item_size.Height + y_spacing)) * cols; + break; + case View.List: + first = (h_marker / (item_size.Width * x_spacing)) * rows; + break; + } + + if (first >= items.Count) + first = items.Count; + + return first; + } for (int i = 0; i < items.Count; i++) { Rectangle item_rect = new Rectangle (GetItemLocation (i), item_size); if (item_rect.Right >= 0 && item_rect.Bottom >= 0) @@ -1125,7 +1100,7 @@ namespace System.Windows.Forms internal void OnSelectedIndexChanged () { - if (IsHandleCreated) + if (is_selection_available) OnSelectedIndexChanged (EventArgs.Empty); } @@ -1142,17 +1117,15 @@ namespace System.Windows.Forms // Avoid calculations when control is being updated if (updating) return; -#if NET_2_0 // VirtualMode doesn't do any calculations until handle is created if (virtual_mode && !IsHandleCreated) return; -#endif if (recalculate) CalculateListView (this.alignment); - Refresh (); + Invalidate (true); } void InvalidateSelection () @@ -1206,7 +1179,6 @@ namespace System.Windows.Forms { Size temp = Size.Empty; Size ret_size = Size.Empty; -#if NET_2_0 bool use_indent_count = small_image_list != null; // VirtualMode uses the first item text size @@ -1218,7 +1190,6 @@ namespace System.Windows.Forms if (use_indent_count) ret_size.Width += item.IndentCount * small_image_list.ImageSize.Width; } else { -#endif // 0th column holds the item text, we check the size of // the various subitems falling in that column and get // the biggest one's size. @@ -1229,17 +1200,13 @@ namespace System.Windows.Forms temp = Size.Ceiling (TextRenderer.MeasureString (item.SubItems [col].Text, Font)); -#if NET_2_0 if (use_indent_count) temp.Width += item.IndentCount * small_image_list.ImageSize.Width; -#endif if (temp.Width > ret_size.Width) ret_size = temp; } -#if NET_2_0 } -#endif // adjustment for space in Details view if (!ret_size.IsEmpty && view == View.Details) @@ -1295,33 +1262,36 @@ namespace System.Windows.Forms text_size.Height += 2; } - private void Scroll (ScrollBar scrollbar, int delta) + private void SetScrollValue (ScrollBar scrollbar, int val) { - if (delta == 0 || !scrollbar.Visible) - return; - int max; if (scrollbar == h_scroll) - max = h_scroll.Maximum - item_control.Width; + max = h_scroll.Maximum - h_scroll.LargeChange + 1; else - max = v_scroll.Maximum - item_control.Height; + max = v_scroll.Maximum - v_scroll.LargeChange + 1; - int val = scrollbar.Value + delta; if (val > max) val = max; else if (val < scrollbar.Minimum) val = scrollbar.Minimum; + scrollbar.Value = val; } - private void CalculateScrollBars () + private void Scroll (ScrollBar scrollbar, int delta) { - if (!IsHandleCreated) + if (delta == 0 || !scrollbar.Visible) return; + SetScrollValue (scrollbar, scrollbar.Value + delta); + } + + private void CalculateScrollBars () + { Rectangle client_area = ClientRectangle; int height = client_area.Height; int width = client_area.Width; + Size item_size; if (!scrollable) { h_scroll.Visible = false; @@ -1355,6 +1325,8 @@ namespace System.Windows.Forms } + item_size = ItemSize; + if (h_scroll.is_visible) { h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height); h_scroll.Minimum = 0; @@ -1370,8 +1342,12 @@ namespace System.Windows.Forms h_scroll.Width = client_area.Width; } + if (view == View.List) + h_scroll.SmallChange = item_size.Width + ThemeEngine.Current.ListViewHorizontalSpacing; + else + h_scroll.SmallChange = Font.Height; + h_scroll.LargeChange = client_area.Width; - h_scroll.SmallChange = Font.Height; height -= h_scroll.Height; } @@ -1379,18 +1355,25 @@ namespace System.Windows.Forms v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y); v_scroll.Minimum = 0; - // if h_scroll is visible, adjust the maximum of the + // if h_scroll is visible, adjust the height of // v_scroll to account for the height of h_scroll if (h_scroll.Visible) { v_scroll.Maximum = layout_ht + h_scroll.Height; - v_scroll.Height = client_area.Height; // - h_scroll.Height already done + v_scroll.Height = client_area.Height > h_scroll.Height ? client_area.Height - h_scroll.Height : 0; } else { v_scroll.Maximum = layout_ht; v_scroll.Height = client_area.Height; } - v_scroll.LargeChange = client_area.Height; - v_scroll.SmallChange = Font.Height; + if (view == View.Details) { + // Need to update Maximum if using LargeChange with value other than the visible area + int headerPlusOneItem = header_control.Height + item_size.Height; + v_scroll.LargeChange = v_scroll.Height > headerPlusOneItem ? v_scroll.Height - headerPlusOneItem : 0; + v_scroll.Maximum = v_scroll.Maximum > headerPlusOneItem ? v_scroll.Maximum - headerPlusOneItem : 0; + } else + v_scroll.LargeChange = v_scroll.Height; + + v_scroll.SmallChange = item_size.Height; width -= v_scroll.Width; } @@ -1400,7 +1383,6 @@ namespace System.Windows.Forms header_control.Width = width; } -#if NET_2_0 internal int GetReorderedColumnIndex (ColumnHeader column) { if (reordered_column_indices == null) @@ -1412,7 +1394,6 @@ namespace System.Windows.Forms return -1; } -#endif internal ColumnHeader GetReorderedColumn (int index) { @@ -1424,7 +1405,6 @@ namespace System.Windows.Forms internal void ReorderColumn (ColumnHeader col, int index, bool fireEvent) { -#if NET_2_0 if (fireEvent) { ColumnReorderedEventHandler eh = (ColumnReorderedEventHandler) (Events [ColumnReorderedEvent]); if (eh != null){ @@ -1438,7 +1418,6 @@ namespace System.Windows.Forms } } } -#endif int column_count = Columns.Count; if (reordered_column_indices == null) { @@ -1533,7 +1512,6 @@ namespace System.Windows.Forms } } -#if NET_2_0 Size TileItemSize { get { // Calculate tile size if needed @@ -1551,7 +1529,6 @@ namespace System.Windows.Forms return tile_size; } } -#endif int GetDetailsItemHeight () { @@ -1569,9 +1546,6 @@ namespace System.Windows.Forms if (old_location.X == x && old_location.Y == y) return; - Size item_size = ItemSize; - Rectangle old_rect = new Rectangle (GetItemLocation (index), item_size); - items_location [index] = new Point (x, y); items_matrix_location [index] = new ItemMatrixLocation (row, col); @@ -1579,13 +1553,9 @@ namespace System.Windows.Forms // Initial position matches item's position in ListViewItemCollection // reordered_items_indices [index] = index; - - // Invalidate both previous and new bounds - item_control.Invalidate (old_rect); - item_control.Invalidate (new Rectangle (GetItemLocation (index), item_size)); } -#if NET_2_0 + void ShiftItemsPositions (int from, int to, bool forward) { if (forward) { @@ -1593,18 +1563,18 @@ namespace System.Windows.Forms reordered_items_indices [i] = reordered_items_indices [i - 1]; ListViewItem item = items [reordered_items_indices [i]]; - item_control.Invalidate (item.Bounds); + item.Invalidate (); item.DisplayIndex = i; - item_control.Invalidate (item.Bounds); + item.Invalidate (); } } else { for (int i = from - 1; i < to; i++) { reordered_items_indices [i] = reordered_items_indices [i + 1]; ListViewItem item = items [reordered_items_indices [i]]; - item_control.Invalidate (item.Bounds); + item.Invalidate (); item.DisplayIndex = i; - item_control.Invalidate (item.Bounds); + item.Invalidate (); } } } @@ -1632,9 +1602,9 @@ namespace System.Windows.Forms reordered_items_indices [new_display_index] = item_index; - item_control.Invalidate (item.Bounds); + item.Invalidate (); item.DisplayIndex = new_display_index; - item_control.Invalidate (item.Bounds); + item.Invalidate (); } int GetDisplayIndexFromLocation (Point loc) @@ -1680,8 +1650,10 @@ namespace System.Windows.Forms return count; } -#endif + // cache the spacing to let virtualmode compute the positions on the fly + int x_spacing; + int y_spacing; int rows; int cols; int[,] item_index_matrix; @@ -1692,16 +1664,16 @@ namespace System.Windows.Forms if (UseCustomColumnWidth) CalculateCustomColumnWidth (); -#if NET_2_0 - if (show_groups && groups.Count > 0 && view != View.List) { + if (UsingGroups) { // When groups are used the alignment is always top-aligned rows = 0; cols = 0; + int items = 0; groups.DefaultGroup.ItemCount = GetDefaultGroupItems (); for (int i = 0; i < groups.InternalCount; i++) { ListViewGroup group = groups.GetInternalGroup (i); - int items_in_group = group.ItemCount; + int items_in_group = group.GetActualItemCount (); if (items_in_group == 0) continue; @@ -1713,12 +1685,14 @@ namespace System.Windows.Forms group.starting_row = rows; group.rows = group_rows; + group.starting_item = items; + group.current_item = 0; // Reset layout cols = Math.Max (group_cols, cols); rows += group_rows; + items += items_in_group; } } else -#endif { // Simple matrix if no groups are used if (left_aligned) { @@ -1763,30 +1737,34 @@ namespace System.Windows.Forms item_control.Visible = true; item_control.Location = Point.Empty; ItemSize = item_size; // Cache item size + this.x_spacing = x_spacing; + this.y_spacing = y_spacing; if (items.Count == 0) return; Size sz = item_size; -#if NET_2_0 - bool using_groups = show_groups && groups.Count > 0 && view != View.List; -#endif CalculateRowsAndCols (sz, left_aligned, x_spacing, y_spacing); layout_wd = UseCustomColumnWidth ? cols * custom_column_width : cols * (sz.Width + x_spacing) - x_spacing; layout_ht = rows * (sz.Height + y_spacing) - y_spacing; -#if NET_2_0 - if (using_groups) + + if (virtual_mode) { // no actual assignment is needed on items for virtual mode + item_control.Size = new Size (layout_wd, layout_ht); + return; + } + + bool using_groups = UsingGroups; + if (using_groups) // the groups layout will override layout_ht CalculateGroupsLayout (sz, y_spacing, 0); -#endif int row = 0, col = 0; int x = 0, y = 0; + int display_index = 0; for (int i = 0; i < items.Count; i++) { ListViewItem item = items [i]; -#if NET_2_0 if (using_groups) { ListViewGroup group = item.Group; if (group == null) @@ -1796,19 +1774,22 @@ namespace System.Windows.Forms int current_item = group.current_item++; int starting_row = group.starting_row; + display_index = group.starting_item + current_item; row = (current_item / cols); col = current_item % cols; x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing); y = row * (item_size.Height + y_spacing) + group_items_loc.Y; - SetItemLocation (i, x, y, row + starting_row, col); + SetItemLocation (display_index, x, y, row + starting_row, col); + SetItemAtDisplayIndex (display_index, i); item_index_matrix [row + starting_row, col] = i; + } else -#endif { x = UseCustomColumnWidth ? col * custom_column_width : col * (item_size.Width + x_spacing); y = row * (item_size.Height + y_spacing); + display_index = i; // Same as item index in Items SetItemLocation (i, x, y, row, col); item_index_matrix [row, col] = i; @@ -1826,22 +1807,15 @@ namespace System.Windows.Forms } } } -#if NET_2_0 - if (!virtual_mode) -#endif - { - item.Layout (); - item.DisplayIndex = i; - item.SetPosition (new Point (x, y)); - } - + item.Layout (); + item.DisplayIndex = display_index; + item.SetPosition (new Point (x, y)); } item_control.Size = new Size (layout_wd, layout_ht); } -#if NET_2_0 void CalculateGroupsLayout (Size item_size, int y_spacing, int y_origin) { int y = y_origin; @@ -1852,7 +1826,6 @@ namespace System.Windows.Forms if (group.ItemCount == 0) continue; - group.current_item = 0; // Reset layout y += LayoutGroupHeader (group, y, item_size.Height, y_spacing, details ? group.ItemCount : group.rows); } @@ -1862,7 +1835,7 @@ namespace System.Windows.Forms int LayoutGroupHeader (ListViewGroup group, int y_origin, int item_height, int y_spacing, int rows) { Rectangle client_area = ClientRectangle; - int header_height = text_size.Height + 10; + int header_height = Font.Height + 15; // one line height + some padding group.HeaderBounds = new Rectangle (0, y_origin, client_area.Width - v_scroll.Width, header_height); group.items_area_location = new Point (0, y_origin + header_height); @@ -1870,7 +1843,24 @@ namespace System.Windows.Forms int items_area_height = ((item_height + y_spacing) * rows); return header_height + items_area_height + 10; // Add a small bottom margin } -#endif + + void CalculateDetailsGroupItemsCount () + { + int items = 0; + + groups.DefaultGroup.ItemCount = GetDefaultGroupItems (); + for (int i = 0; i < groups.InternalCount; i++) { + ListViewGroup group = groups.GetInternalGroup (i); + int items_in_group = group.GetActualItemCount (); + + if (items_in_group == 0) + continue; + + group.starting_item = items; + group.current_item = 0; // Reset layout. + items += items_in_group; + } + } void LayoutHeader () { @@ -1894,7 +1884,7 @@ namespace System.Windows.Forms layout_wd = ClientRectangle.Width; } else { header_control.Width = x; - header_control.Height = columns.Count > 0 ? columns [0].Ht : Font.Height + 5; + header_control.Height = columns.Count > 0 ? columns [0].Ht : ThemeEngine.Current.ListViewGetHeaderHeight (this, Font); header_control.Visible = true; } } @@ -1913,27 +1903,31 @@ namespace System.Windows.Forms item_control.Visible = true; item_control.Location = Point.Empty; item_control.Width = ClientRectangle.Width; + AdjustChildrenZOrder (); int item_height = GetDetailsItemHeight (); ItemSize = new Size (0, item_height); // We only cache Height for details view int y = header_control.Height; -#if NET_2_0 - bool using_groups = show_groups && groups.Count > 0 && view != View.List; - if (using_groups) + layout_ht = y + (item_height * items.Count); + if (items.Count > 0 && grid_lines) // some space for bottom gridline + layout_ht += 2; + + bool using_groups = UsingGroups; + if (using_groups) { + // Observe that this routines will override our layout_ht value + CalculateDetailsGroupItemsCount (); CalculateGroupsLayout (ItemSize, 2, y); -#endif + } + + if (virtual_mode) // no assgination on items is needed + return; for (int i = 0; i < items.Count; i++) { ListViewItem item = items [i]; -#if NET_2_0 - if (!virtual_mode) // Virtual mode sets Layout until draw time -#endif - { - item.Layout (); - item.DisplayIndex = i; - } -#if NET_2_0 + int display_index; + int item_y; + if (using_groups) { ListViewGroup group = item.Group; if (group == null) @@ -1941,31 +1935,43 @@ namespace System.Windows.Forms int current_item = group.current_item++; Point group_items_loc = group.items_area_location; + display_index = group.starting_item + current_item; - y = current_item * (item_height + 2) + group_items_loc.Y; - SetItemLocation (i, 0, y, 0, 0); - item.SetPosition (new Point (0, y)); + y = item_y = current_item * (item_height + 2) + group_items_loc.Y; + SetItemLocation (display_index, 0, item_y, 0, 0); + SetItemAtDisplayIndex (display_index, i); } else -#endif { - SetItemLocation (i, 0, y, 0, 0); - item.SetPosition (new Point (0, y)); + display_index = i; + item_y = y; + SetItemLocation (i, 0, item_y, 0, 0); y += item_height; } - } - // some space for bottom gridline - if (items.Count > 0 && grid_lines) - y += 2; + item.Layout (); + item.DisplayIndex = display_index; + item.SetPosition (new Point (0, item_y)); + } + } -#if NET_2_0 - if (!using_groups) // With groups it has been previously computed -#endif - layout_ht = y; + // Need to make sure HeaderControl is on top, and we can't simply use BringToFront since + // these controls are implicit, so we need to re-populate our collection. + void AdjustChildrenZOrder () + { + SuspendLayout (); + Controls.ClearImplicit (); + Controls.AddImplicit (header_control); + Controls.AddImplicit (item_control); + Controls.AddImplicit (h_scroll); + Controls.AddImplicit (v_scroll); + ResumeLayout (); } private void AdjustItemsPositionArray (int count) { + // In virtual mode we compute the positions on the fly. + if (virtual_mode) + return; if (items_location.Length >= count) return; @@ -2002,13 +2008,14 @@ namespace System.Windows.Forms LayoutIcons (SmallIconItemSize, true, ThemeEngine.Current.ListViewHorizontalSpacing, 2); break; -#if NET_2_0 case View.Tile: + if (!Application.VisualStylesEnabled) + goto case View.LargeIcon; + LayoutIcons (TileItemSize, alignment == ListViewAlignment.Left, ThemeEngine.Current.ListViewHorizontalSpacing, ThemeEngine.Current.ListViewVerticalSpacing); break; -#endif } CalculateScrollBars (); @@ -2016,18 +2023,60 @@ namespace System.Windows.Forms internal Point GetItemLocation (int index) { - Point loc = items_location [index]; + Point loc = Point.Empty; + if (virtual_mode) + loc = GetFixedItemLocation (index); + else + loc = items_location [index]; + loc.X -= h_marker; // Adjust to scroll loc.Y -= v_marker; return loc; } + Point GetFixedItemLocation (int index) + { + Point loc = Point.Empty; + + switch (view) { + case View.LargeIcon: + case View.SmallIcon: + loc.X = index % cols * (item_size.Width + x_spacing); + loc.Y = index / cols * (item_size.Height + y_spacing); + break; + case View.List: + loc.X = index / rows * (item_size.Width + x_spacing); + loc.Y = index % rows * (item_size.Height + y_spacing); + break; + case View.Details: + loc.Y = header_control.Height + (index * item_size.Height); + break; + } + + return loc; + } + internal int GetItemIndex (int display_index) { + if (virtual_mode) + return display_index; // no reordering in virtual mode. return reordered_items_indices [display_index]; } + internal ListViewItem GetItemAtDisplayIndex (int display_index) + { + // in virtual mode there's no reordering at all. + if (virtual_mode) + return items [display_index]; + return items [reordered_items_indices [display_index]]; + } + + internal void SetItemAtDisplayIndex (int display_index, int index) + { + reordered_items_indices [display_index] = index; + } + private bool KeySearchString (KeyEventArgs ke) { int current_tickcnt = Environment.TickCount; @@ -2041,24 +2090,31 @@ namespace System.Windows.Forms keysearch_text += (char)ke.KeyCode; keysearch_tickcnt = current_tickcnt; - int start = FocusedItem == null ? 0 : FocusedItem.Index; - int i = start; - while (true) { - if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (Items[i].Text, keysearch_text, - CompareOptions.IgnoreCase)) { - SetFocusedItem (i); - items [i].Selected = true; - EnsureVisible (i); - break; - } - i = (i + 1 < Items.Count) ? i+1 : 0; + int prev_focused = FocusedItem == null ? 0 : FocusedItem.DisplayIndex; + int start = prev_focused + 1 < Items.Count ? prev_focused + 1 : 0; - if (i == start) - break; + ListViewItem item = FindItemWithText (keysearch_text, false, start, true, true); + if (item != null && prev_focused != item.DisplayIndex) { + selected_indices.Clear (); + + SetFocusedItem (item.DisplayIndex); + item.Selected = true; + EnsureVisible (GetItemIndex (item.DisplayIndex)); } + return true; } + private void OnItemsChanged () + { + ResetSearchString (); + } + + private void ResetSearchString () + { + keysearch_text = String.Empty; + } + int GetAdjustedIndex (Keys key) { int result = -1; @@ -2066,10 +2122,10 @@ namespace System.Windows.Forms if (View == View.Details) { switch (key) { case Keys.Up: - result = FocusedItem.Index - 1; + result = FocusedItem.DisplayIndex - 1; break; case Keys.Down: - result = FocusedItem.Index + 1; + result = FocusedItem.DisplayIndex + 1; if (result == items.Count) result = -1; break; @@ -2078,10 +2134,10 @@ namespace System.Windows.Forms Rectangle item_rect = new Rectangle (GetItemLocation (last_index), ItemSize); if (item_rect.Bottom > item_control.ClientRectangle.Bottom) last_index--; - if (FocusedItem.Index == last_index) { - if (FocusedItem.Index < Items.Count - 1) { + if (FocusedItem.DisplayIndex == last_index) { + if (FocusedItem.DisplayIndex < Items.Count - 1) { int page_size = item_control.Height / ItemSize.Height - 1; - result = FocusedItem.Index + page_size - 1; + result = FocusedItem.DisplayIndex + page_size - 1; if (result >= Items.Count) result = Items.Count - 1; } @@ -2092,7 +2148,7 @@ namespace System.Windows.Forms int first_index = FirstVisibleIndex; if (GetItemLocation (first_index).Y < 0) first_index++; - if (FocusedItem.Index == first_index) { + if (FocusedItem.DisplayIndex == first_index) { if (first_index > 0) { int page_size = item_control.Height / ItemSize.Height - 1; result = first_index - page_size + 1; @@ -2106,15 +2162,21 @@ namespace System.Windows.Forms return result; } - ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.Index]; + if (virtual_mode) + return GetFixedAdjustedIndex (key); + + ItemMatrixLocation item_matrix_location = items_matrix_location [FocusedItem.DisplayIndex]; int row = item_matrix_location.Row; int col = item_matrix_location.Col; + int adjusted_index = -1; + switch (key) { case Keys.Left: if (col == 0) return -1; - return item_index_matrix [row, col - 1]; + adjusted_index = item_index_matrix [row, col - 1]; + break; case Keys.Right: if (col == (cols - 1)) @@ -2124,7 +2186,8 @@ namespace System.Windows.Forms if (row < 0) return -1; } - return item_index_matrix [row, col + 1]; + adjusted_index = item_index_matrix [row, col + 1]; + break; case Keys.Up: if (row == 0) @@ -2134,7 +2197,8 @@ namespace System.Windows.Forms if (col < 0) return -1; } - return item_index_matrix [row - 1, col]; + adjusted_index = item_index_matrix [row - 1, col]; + break; case Keys.Down: if (row == (rows - 1) || row == Items.Count - 1) @@ -2144,11 +2208,55 @@ namespace System.Windows.Forms if (col < 0) return -1; } - return item_index_matrix [row + 1, col]; + adjusted_index = item_index_matrix [row + 1, col]; + break; default: return -1; } + + return items [adjusted_index].DisplayIndex; + } + + // Used for virtual mode, where items *cannot* be re-arranged + int GetFixedAdjustedIndex (Keys key) + { + int result; + + switch (key) { + case Keys.Left: + if (view == View.List) + result = focused_item_index - rows; + else + result = focused_item_index - 1; + break; + case Keys.Right: + if (view == View.List) + result = focused_item_index + rows; + else + result = focused_item_index + 1; + break; + case Keys.Up: + if (view != View.List) + result = focused_item_index - cols; + else + result = focused_item_index - 1; + break; + case Keys.Down: + if (view != View.List) + result = focused_item_index + cols; + else + result = focused_item_index + 1; + break; + default: + return -1; + + } + + if (result < 0 || result >= items.Count) + result = focused_item_index; + + return result; } ListViewItem selection_start; @@ -2173,16 +2281,16 @@ namespace System.Windows.Forms { bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0; bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0; - ListViewItem item = items [index]; + ListViewItem item = GetItemAtDisplayIndex (index); if (shift_pressed && selection_start != null) { ArrayList list = new ArrayList (); - int start_index = selection_start.Index; + int start_index = selection_start.DisplayIndex; int start = Math.Min (start_index, index); int end = Math.Max (start_index, index); if (View == View.Details) { for (int i = start; i <= end; i++) - list.Add (items [i]); + list.Add (GetItemAtDisplayIndex (i)); } else { ItemMatrixLocation start_item_matrix_location = items_matrix_location [start]; ItemMatrixLocation end_item_matrix_location = items_matrix_location [end]; @@ -2196,7 +2304,7 @@ namespace System.Windows.Forms if (item_matrix_loc.Row >= top && item_matrix_loc.Row <= bottom && item_matrix_loc.Col >= left && item_matrix_loc.Col <= right) - list.Add (items [i]); + list.Add (GetItemAtDisplayIndex (i)); } } SelectItems (list); @@ -2257,6 +2365,7 @@ namespace System.Windows.Forms break; case Keys.Space: + SelectIndex (focused_item_index); ToggleItemsCheckState (); break; case Keys.Enter: @@ -2294,18 +2403,18 @@ namespace System.Windows.Forms } } - void SelectIndex (int index) + void SelectIndex (int display_index) { - if (index == -1) + if (display_index == -1) return; if (MultiSelect) - UpdateMultiSelection (index, true); - else if (!items [index].Selected) - items [index].Selected = true; + UpdateMultiSelection (display_index, true); + else if (!GetItemAtDisplayIndex (display_index).Selected) + GetItemAtDisplayIndex (display_index).Selected = true; - SetFocusedItem (index); - EnsureVisible (index); + SetFocusedItem (display_index); + EnsureVisible (GetItemIndex (display_index)); // Index in Items collection, not display index } private void ListView_KeyDown (object sender, KeyEventArgs ke) @@ -2333,9 +2442,7 @@ namespace System.Windows.Forms bool hover_processed = false; bool checking = false; ListViewItem prev_hovered_item; -#if NET_2_0 ListViewItem prev_tooltip_item; -#endif int clicks; Point drag_begin = new Point (-1, -1); internal int dragged_item_index = -1; @@ -2347,6 +2454,7 @@ namespace System.Windows.Forms public ItemControl (ListView owner) { this.owner = owner; + this.SetStyle (ControlStyles.DoubleBuffer, true); DoubleClick += new EventHandler(ItemsDoubleClick); MouseDown += new MouseEventHandler(ItemsMouseDown); MouseMove += new MouseEventHandler(ItemsMouseMove); @@ -2428,7 +2536,7 @@ namespace System.Windows.Forms bool BoxIntersectsText (int index) { - Rectangle r = owner.Items [index].TextBounds; + Rectangle r = owner.GetItemAtDisplayIndex (index).TextBounds; return BoxSelectRectangle.IntersectsWith (r); } @@ -2437,13 +2545,14 @@ namespace System.Windows.Forms ArrayList result = new ArrayList (); for (int i = 0; i < owner.Items.Count; i++) { bool intersects; - if (owner.View == View.Details && !owner.FullRowSelect) + // Can't iterate over specific items properties in virtualmode + if (owner.View == View.Details && !owner.FullRowSelect && !owner.VirtualMode) intersects = BoxIntersectsText (i); else intersects = BoxIntersectsItem (i); if (intersects) - result.Add (owner.Items [i]); + result.Add (owner.GetItemAtDisplayIndex (i)); } return result; } @@ -2510,16 +2619,13 @@ namespace System.Windows.Forms continue; // Actual item in 'i' position - ListViewItem item = owner.items [owner.reordered_items_indices [i]]; + ListViewItem item = owner.GetItemAtDisplayIndex (i); if (item.CheckRectReal.Contains (pt)) { // Don't modify check state if we have only one image // and if we are in 1.1 profile only take into account // double clicks if (owner.StateImageList != null && owner.StateImageList.Images.Count < 2 -#if !NET_2_0 - && me.Clicks == 1 -#endif ) return; @@ -2536,7 +2642,7 @@ namespace System.Windows.Forms if (owner.View == View.Details) { bool over_text = item.TextBounds.Contains (pt); if (owner.FullRowSelect) { - clicked_item = owner.items [i]; + clicked_item = item; bool over_item_column = (me.X > owner.Columns[0].X && me.X < owner.Columns[0].X + owner.Columns[0].Width); if (!over_text && over_item_column && owner.MultiSelect) box_selecting = true; @@ -2554,17 +2660,16 @@ namespace System.Windows.Forms if (clicked_item != null) { bool changed = !clicked_item.Selected; if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed)) - owner.SetFocusedItem (clicked_item.Index); + owner.SetFocusedItem (clicked_item.DisplayIndex); if (owner.MultiSelect) { bool reselect = (!owner.LabelEdit || changed); if (me.Button == MouseButtons.Left || (XplatUI.State.ModifierKeys == Keys.None && changed)) - owner.UpdateMultiSelection (clicked_item.Index, reselect); + owner.UpdateMultiSelection (clicked_item.DisplayIndex, reselect); } else { clicked_item.Selected = true; } -#if NET_2_0 if (owner.VirtualMode && changed) { // Broken event - It's not fired from Item.Selected also ListViewVirtualItemsSelectionRangeChangedEventArgs args = @@ -2572,7 +2677,6 @@ namespace System.Windows.Forms owner.OnVirtualItemsSelectionRangeChanged (args); } -#endif // Report clicks only if the item was clicked. On MS the // clicks are only raised if you click an item clicks = me.Clicks; @@ -2583,6 +2687,9 @@ namespace System.Windows.Forms if (owner.LabelEdit && !changed) BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit } + + drag_begin = me.Location; + dragged_item_index = clicked_item.Index; } else { if (owner.MultiSelect) box_selecting = true; @@ -2613,9 +2720,7 @@ namespace System.Windows.Forms return; if ((me.Button != MouseButtons.Left && me.Button != MouseButtons.Right) && !hover_processed && owner.Activation != ItemActivation.OneClick -#if NET_2_0 && !owner.ShowItemToolTips -#endif ) return; @@ -2630,18 +2735,14 @@ namespace System.Windows.Forms // Need to invalidate the item in HotTracking to show/hide the underline style if (owner.Activation == ItemActivation.OneClick) { if (item == null && owner.HotItemIndex != -1) { -#if NET_2_0 if (owner.HotTracking) Invalidate (owner.Items [owner.HotItemIndex].Bounds); // Previous one -#endif Cursor = Cursors.Default; owner.HotItemIndex = -1; } else if (item != null && owner.HotItemIndex == -1) { -#if NET_2_0 if (owner.HotTracking) Invalidate (item.Bounds); -#endif Cursor = Cursors.Hand; owner.HotItemIndex = item.Index; @@ -2649,13 +2750,7 @@ namespace System.Windows.Forms } if (me.Button == MouseButtons.Left || me.Button == MouseButtons.Right) { - if (drag_begin.X == -1 && drag_begin.Y == -1) { - if (item != null) { - drag_begin = new Point (me.X, me.Y); - dragged_item_index = item.Index; - } - - } else { + if (drag_begin != new Point (-1, -1)) { Rectangle r = new Rectangle (drag_begin, SystemInformation.DragSize); if (!r.Contains (me.X, me.Y)) { ListViewItem dragged_item = owner.items [dragged_item_index]; @@ -2667,7 +2762,6 @@ namespace System.Windows.Forms } } -#if NET_2_0 if (owner.ShowItemToolTips) { if (item == null) { owner.item_tooltip.Active = false; @@ -2678,7 +2772,6 @@ namespace System.Windows.Forms prev_tooltip_item = item; } } -#endif } @@ -2706,13 +2799,11 @@ namespace System.Windows.Forms else item.Selected = true; - owner.SetFocusedItem (item.Index); + owner.SetFocusedItem (item.DisplayIndex); Select (); // Make sure we have the focus, since MouseHover doesn't give it to us } -#if NET_2_0 owner.OnItemMouseHover (new ListViewItemMouseHoverEventArgs (item)); -#endif } void HandleClicks (MouseEventArgs me) @@ -2720,17 +2811,11 @@ namespace System.Windows.Forms // if the click is not on an item, // clicks remains as 0 if (clicks > 1) { -#if !NET_2_0 - owner.OnDoubleClick (EventArgs.Empty); - } else if (clicks == 1) { - owner.OnClick (EventArgs.Empty); -#else owner.OnDoubleClick (EventArgs.Empty); owner.OnMouseDoubleClick (me); } else if (clicks == 1) { owner.OnClick (EventArgs.Empty); owner.OnMouseClick (me); -#endif } clicks = 0; @@ -3145,12 +3230,20 @@ namespace System.Windows.Forms ListViewItem focused_item = FocusedItem; if (focused_item.ListView != null) { - item_control.Invalidate (focused_item.Bounds); + focused_item.Invalidate (); focused_item.Layout (); - item_control.Invalidate (focused_item.Bounds); + focused_item.Invalidate (); } } + private void ListView_Invalidated (object sender, InvalidateEventArgs e) + { + // When the ListView is invalidated, we need to invalidate + // the child controls. + header_control.Invalidate (); + item_control.Invalidate (); + } + private void ListView_MouseEnter (object sender, EventArgs args) { hover_pending = true; // Need a hover event for every Enter/Leave cycle @@ -3177,27 +3270,31 @@ namespace System.Windows.Forms case View.List: Scroll (h_scroll, -ItemSize.Width * lines); break; -#if NET_2_0 case View.Tile: + if (!Application.VisualStylesEnabled) + goto case View.LargeIcon; + Scroll (v_scroll, -(ItemSize.Height + ThemeEngine.Current.ListViewVerticalSpacing) * 2 * lines); break; -#endif } } private void ListView_SizeChanged (object sender, EventArgs e) { - CalculateListView (alignment); + Redraw (true); } - private void SetFocusedItem (int index) + private void SetFocusedItem (int display_index) { - if (index != -1) - items [index].Focused = true; + if (display_index != -1) + GetItemAtDisplayIndex (display_index).Focused = true; else if (focused_item_index != -1 && focused_item_index < items.Count) // Previous focused item - items [focused_item_index].Focused = false; - - focused_item_index = index; + GetItemAtDisplayIndex (focused_item_index).Focused = false; + focused_item_index = display_index; + if (display_index == -1) + OnUIAFocusedItemChanged (); + // otherwise the event will have been fired + // when the ListViewItem's Focused was set } private void HorizontalScroller (object sender, EventArgs e) @@ -3247,6 +3344,7 @@ namespace System.Windows.Forms protected override void CreateHandle () { base.CreateHandle (); + is_selection_available = true; for (int i = 0; i < SelectedItems.Count; i++) OnSelectedIndexChanged (EventArgs.Empty); } @@ -3254,9 +3352,6 @@ namespace System.Windows.Forms protected override void Dispose (bool disposing) { if (disposing) { - h_scroll.Dispose (); - v_scroll.Dispose (); - large_image_list = null; small_image_list = null; state_image_list = null; @@ -3264,9 +3359,7 @@ namespace System.Windows.Forms foreach (ColumnHeader col in columns) col.SetListView (null); -#if NET_2_0 if (!virtual_mode) // In virtual mode we don't save the items -#endif foreach (ListViewItem item in items) item.Owner = null; } @@ -3301,13 +3394,11 @@ namespace System.Windows.Forms eh (this, e); } -#if NET_2_0 protected override void OnBackgroundImageChanged (EventArgs e) { item_control.BackgroundImage = BackgroundImage; base.OnBackgroundImageChanged (e); } -#endif protected virtual void OnBeforeLabelEdit (LabelEditEventArgs e) { @@ -3316,14 +3407,13 @@ namespace System.Windows.Forms eh (this, e); } - protected virtual void OnColumnClick (ColumnClickEventArgs e) + protected internal virtual void OnColumnClick (ColumnClickEventArgs e) { ColumnClickEventHandler eh = (ColumnClickEventHandler)(Events [ColumnClickEvent]); if (eh != null) eh (this, e); } -#if NET_2_0 protected internal virtual void OnDrawColumnHeader(DrawListViewColumnHeaderEventArgs e) { DrawListViewColumnHeaderEventHandler eh = (DrawListViewColumnHeaderEventHandler)(Events[DrawColumnHeaderEvent]); @@ -3345,13 +3435,6 @@ namespace System.Windows.Forms eh(this, e); } -#else - protected override void OnEnabledChanged (EventArgs e) - { - base.OnEnabledChanged (e); - } -#endif - protected override void OnFontChanged (EventArgs e) { base.OnFontChanged (e); @@ -3362,9 +3445,7 @@ namespace System.Windows.Forms { base.OnHandleCreated (e); CalculateListView (alignment); -#if NET_2_0 if (!virtual_mode) // Sorting is not allowed in virtual mode -#endif Sort (); } @@ -3387,14 +3468,12 @@ namespace System.Windows.Forms eh (this, ice); } -#if NET_2_0 protected internal virtual void OnItemChecked (ItemCheckedEventArgs e) { ItemCheckedEventHandler eh = (ItemCheckedEventHandler)(Events [ItemCheckedEvent]); if (eh != null) eh (this, e); } -#endif protected virtual void OnItemDrag (ItemDragEventArgs e) { @@ -3403,7 +3482,6 @@ namespace System.Windows.Forms eh (this, e); } -#if NET_2_0 protected virtual void OnItemMouseHover (ListViewItemMouseHoverEventArgs e) { ListViewItemMouseHoverEventHandler eh = (ListViewItemMouseHoverEventHandler)(Events [ItemMouseHoverEvent]); @@ -3428,7 +3506,6 @@ namespace System.Windows.Forms { base.OnParentChanged (e); } -#endif protected virtual void OnSelectedIndexChanged (EventArgs e) { @@ -3442,10 +3519,9 @@ namespace System.Windows.Forms base.OnSystemColorsChanged (e); } -#if NET_2_0 - protected virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e) + protected internal virtual void OnCacheVirtualItems (CacheVirtualItemsEventArgs e) { - EventHandler eh = (EventHandler)Events [CacheVirtualItemsEvent]; + CacheVirtualItemsEventHandler eh = (CacheVirtualItemsEventHandler)Events [CacheVirtualItemsEvent]; if (eh != null) eh (this, e); } @@ -3479,7 +3555,6 @@ namespace System.Windows.Forms if (eh != null) eh (this, e); } -#endif protected void RealizeProperties () { @@ -3527,14 +3602,10 @@ namespace System.Windows.Forms public void ArrangeIcons (ListViewAlignment value) { // Icons are arranged only if view is set to LargeIcon or SmallIcon - if (view == View.LargeIcon || view == View.SmallIcon) { - this.CalculateListView (value); - // we have done the calculations already - this.Redraw (false); - } + if (view == View.LargeIcon || view == View.SmallIcon) + Redraw (true); } -#if NET_2_0 public void AutoResizeColumn (int columnIndex, ColumnHeaderAutoResizeStyle headerAutoResize) { if (columnIndex < 0 || columnIndex >= columns.Count) @@ -3550,7 +3621,6 @@ namespace System.Windows.Forms col.AutoResize (headerAutoResize); EndUpdate (); } -#endif public void BeginUpdate () { @@ -3575,11 +3645,17 @@ namespace System.Windows.Forms public void EnsureVisible (int index) { - if (index < 0 || index >= items.Count || scrollable == false) + if (index < 0 || index >= items.Count || scrollable == false || updating) return; Rectangle view_rect = item_control.ClientRectangle; - Rectangle bounds = new Rectangle (GetItemLocation (index), ItemSize); + // Avoid direct access to items in virtual mode, and use item bounds otherwise, since we could have reordered items + Rectangle bounds = virtual_mode ? new Rectangle (GetItemLocation (index), ItemSize) : items [index].Bounds; + + if (view == View.Details && header_style != ColumnHeaderStyle.None) { + view_rect.Y += header_control.Height; + view_rect.Height -= header_control.Height; + } if (view_rect.Contains (bounds)) return; @@ -3591,13 +3667,12 @@ namespace System.Windows.Forms h_scroll.Value += (bounds.Right - view_rect.Right); } - if (bounds.Top < 0) - v_scroll.Value += bounds.Top; + if (bounds.Top < view_rect.Y) + v_scroll.Value += bounds.Top - view_rect.Y; else if (bounds.Bottom > view_rect.Bottom) v_scroll.Value += (bounds.Bottom - view_rect.Bottom); } -#if NET_2_0 public ListViewItem FindItemWithText (string text) { if (items.Count == 0) @@ -3608,10 +3683,15 @@ namespace System.Windows.Forms public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex) { - return FindItemWithText (text, includeSubItemsInSearch, startIndex, true); + return FindItemWithText (text, includeSubItemsInSearch, startIndex, true, false); } public ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch) + { + return FindItemWithText (text, includeSubItemsInSearch, startIndex, isPrefixSearch, false); + } + + internal ListViewItem FindItemWithText (string text, bool includeSubItemsInSearch, int startIndex, bool isPrefixSearch, bool roundtrip) { if (startIndex < 0 || startIndex >= items.Count) throw new ArgumentOutOfRangeException ("startIndex"); @@ -3632,20 +3712,39 @@ namespace System.Windows.Forms return null; } - for (int i = startIndex; i < items.Count; i++) { + int i = startIndex; + while (true) { ListViewItem lvi = items [i]; - if ((isPrefixSearch && lvi.Text.StartsWith (text, true, CultureInfo.CurrentCulture)) // prefix search - || String.Compare (lvi.Text, text, true) == 0) // match + if (isPrefixSearch) { // prefix search + if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (lvi.Text, text, CompareOptions.IgnoreCase)) + return lvi; + } else if (String.Compare (lvi.Text, text, true) == 0) // match return lvi; + + if (i + 1 >= items.Count) { + if (!roundtrip) + break; + + i = 0; + } else + i++; + + if (i == startIndex) + break; } + // Subitems have a minor priority, so we have to do a second linear search + // Also, we don't need to to a roundtrip search for them by now if (includeSubItemsInSearch) { - for (int i = startIndex; i < items.Count; i++) { + for (i = startIndex; i < items.Count; i++) { ListViewItem lvi = items [i]; foreach (ListViewItem.ListViewSubItem sub_item in lvi.SubItems) - if ((isPrefixSearch && sub_item.Text.StartsWith (text, true, CultureInfo.CurrentCulture)) - || String.Compare (sub_item.Text, text, true) == 0) + if (isPrefixSearch) { + if (CultureInfo.CurrentCulture.CompareInfo.IsPrefix (sub_item.Text, + text, CompareOptions.IgnoreCase)) + return lvi; + } else if (String.Compare (sub_item.Text, text, true) == 0) return lvi; } } @@ -3729,7 +3828,6 @@ namespace System.Windows.Forms return item; } -#endif public ListViewItem GetItemAt (int x, int y) { @@ -3757,7 +3855,6 @@ namespace System.Windows.Forms return items [index].GetBounds (portion); } -#if NET_2_0 public ListViewHitTestInfo HitTest (Point point) { return HitTest (point.X, point.Y); @@ -3807,19 +3904,16 @@ namespace System.Windows.Forms return; for (int i = startIndex; i <= endIndex; i++) - item_control.Invalidate (items [i].Bounds); + items [i].Invalidate (); if (!invalidateOnly) Update (); } -#endif public void Sort () { -#if NET_2_0 if (virtual_mode) throw new InvalidOperationException (); -#endif Sort (true); } @@ -3858,7 +3952,7 @@ namespace System.Windows.Forms #region Subclasses - class HeaderControl : Control { + internal class HeaderControl : Control { ListView owner; bool column_resize_active = false; @@ -3867,13 +3961,41 @@ namespace System.Windows.Forms ColumnHeader drag_column; int drag_x; int drag_to_index = -1; + ColumnHeader entered_column_header; public HeaderControl (ListView owner) { this.owner = owner; + this.SetStyle (ControlStyles.DoubleBuffer, true); MouseDown += new MouseEventHandler (HeaderMouseDown); MouseMove += new MouseEventHandler (HeaderMouseMove); MouseUp += new MouseEventHandler (HeaderMouseUp); + MouseLeave += new EventHandler (OnMouseLeave); + } + + internal ColumnHeader EnteredColumnHeader { + get { return entered_column_header; } + private set { + if (entered_column_header == value) + return; + if (ThemeEngine.Current.ListViewHasHotHeaderStyle) { + Region region_to_invalidate = new Region (); + region_to_invalidate.MakeEmpty (); + if (entered_column_header != null) + region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header)); + entered_column_header = value; + if (entered_column_header != null) + region_to_invalidate.Union (GetColumnHeaderInvalidateArea (entered_column_header)); + Invalidate (region_to_invalidate); + region_to_invalidate.Dispose (); + } else + entered_column_header = value; + } + } + + void OnMouseLeave (object sender, EventArgs e) + { + EnteredColumnHeader = null; } private ColumnHeader ColumnAtX (int x) @@ -3919,13 +4041,23 @@ namespace System.Windows.Forms drag_to_index = GetReorderedIndex (clicked_column); } clicked_column.Pressed = true; - Rectangle bounds = clicked_column.Rect; - bounds.X -= owner.h_marker; - Invalidate (bounds); + Invalidate (clicked_column); return; } } + void Invalidate (ColumnHeader columnHeader) + { + Invalidate (GetColumnHeaderInvalidateArea (columnHeader)); + } + + Rectangle GetColumnHeaderInvalidateArea (ColumnHeader columnHeader) + { + Rectangle bounds = columnHeader.Rect; + bounds.X -= owner.h_marker; + return bounds; + } + void StopResize () { column_resize_active = false; @@ -3974,17 +4106,16 @@ namespace System.Windows.Forms ColumnHeader over = ColumnAtX (me.X + owner.h_marker); bool pressed = clicked_column.Pressed; clicked_column.Pressed = over == clicked_column; - if (clicked_column.Pressed ^ pressed) { - Rectangle bounds = clicked_column.Rect; - bounds.X -= owner.h_marker; - Invalidate (bounds); - } + if (clicked_column.Pressed ^ pressed) + Invalidate (clicked_column); } return; } for (int i = 0; i < owner.Columns.Count; i++) { Rectangle zone = owner.Columns [i].Rect; + if (zone.Contains (pt)) + EnteredColumnHeader = owner.Columns [i]; zone.X = zone.Right - 5; zone.Width = 10; if (zone.Contains (pt)) { @@ -4014,9 +4145,7 @@ namespace System.Windows.Forms if (clicked_column != null && clicked_column.Pressed) { clicked_column.Pressed = false; - Rectangle bounds = clicked_column.Rect; - bounds.X -= owner.h_marker; - Invalidate (bounds); + Invalidate (clicked_column); owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index)); } @@ -4084,9 +4213,7 @@ namespace System.Windows.Forms } } -#if NET_2_0 [ListBindable (false)] -#endif public class CheckedIndexCollection : IList, ICollection, IEnumerable { private readonly ListView owner; @@ -4220,9 +4347,7 @@ namespace System.Windows.Forms } } // CheckedIndexCollection -#if NET_2_0 [ListBindable (false)] -#endif public class CheckedListViewItemCollection : IList, ICollection, IEnumerable { private readonly ListView owner; @@ -4253,10 +4378,8 @@ namespace System.Windows.Forms public ListViewItem this [int index] { get { -#if NET_2_0 if (owner.VirtualMode) throw new InvalidOperationException (); -#endif ArrayList checked_items = List; if (index < 0 || index >= checked_items.Count) throw new ArgumentOutOfRangeException ("index"); @@ -4264,14 +4387,12 @@ namespace System.Windows.Forms } } -#if NET_2_0 public virtual ListViewItem this [string key] { get { int idx = IndexOfKey (key); return idx == -1 ? null : (ListViewItem) List [idx]; } } -#endif bool ICollection.IsSynchronized { get { return false; } @@ -4299,19 +4420,15 @@ namespace System.Windows.Forms return List.Contains (item); } -#if NET_2_0 public virtual bool ContainsKey (string key) { return IndexOfKey (key) != -1; } -#endif public void CopyTo (Array dest, int index) { -#if NET_2_0 if (owner.VirtualMode) throw new InvalidOperationException (); -#endif if (!owner.CheckBoxes) return; List.CopyTo (dest, index); @@ -4319,10 +4436,8 @@ namespace System.Windows.Forms public IEnumerator GetEnumerator () { -#if NET_2_0 if (owner.VirtualMode) throw new InvalidOperationException (); -#endif if (!owner.CheckBoxes) return (new ListViewItem [0]).GetEnumerator (); return List.GetEnumerator (); @@ -4369,22 +4484,17 @@ namespace System.Windows.Forms public int IndexOf (ListViewItem item) { -#if NET_2_0 if (owner.VirtualMode) throw new InvalidOperationException (); -#endif if (!owner.CheckBoxes) return -1; return List.IndexOf (item); } -#if NET_2_0 public virtual int IndexOfKey (string key) { -#if NET_2_0 if (owner.VirtualMode) throw new InvalidOperationException (); -#endif if (key == null || key.Length == 0) return -1; @@ -4397,7 +4507,6 @@ namespace System.Windows.Forms return -1; } -#endif #endregion // Public Methods internal ArrayList List { @@ -4425,14 +4534,44 @@ namespace System.Windows.Forms } } // CheckedListViewItemCollection -#if NET_2_0 [ListBindable (false)] -#endif public class ColumnHeaderCollection : IList, ICollection, IEnumerable { internal ArrayList list; private ListView owner; + #region UIA Framework Events + //NOTE: + // We are using Reflection to add/remove internal events. + // Class ListViewProvider uses the events when View is Details. + // + //Event used to generate UIA StructureChangedEvent + static object UIACollectionChangedEvent = new object (); + + internal event CollectionChangeEventHandler UIACollectionChanged { + add { + if (owner != null) + owner.Events.AddHandler (UIACollectionChangedEvent, value); + } + remove { + if (owner != null) + owner.Events.RemoveHandler (UIACollectionChangedEvent, value); + } + } + + internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args) + { + if (owner == null) + return; + + CollectionChangeEventHandler eh + = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent]; + if (eh != null) + eh (owner, args); + } + + #endregion UIA Framework Events + #region Public Constructor public ColumnHeaderCollection (ListView owner) { @@ -4459,7 +4598,6 @@ namespace System.Windows.Forms } } -#if NET_2_0 public virtual ColumnHeader this [string key] { get { int idx = IndexOfKey (key); @@ -4469,7 +4607,6 @@ namespace System.Windows.Forms return (ColumnHeader) list [idx]; } } -#endif bool ICollection.IsSynchronized { get { return true; } @@ -4494,23 +4631,21 @@ namespace System.Windows.Forms { int idx = list.Add (value); owner.AddColumn (value, idx, true); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + return idx; } -#if NET_2_0 public virtual ColumnHeader Add (string text, int width, HorizontalAlignment textAlign) { string str = text; -#else - public virtual ColumnHeader Add (string str, int width, HorizontalAlignment textAlign) - { -#endif ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width); this.Add (colHeader); return colHeader; } -#if NET_2_0 public virtual ColumnHeader Add (string text) { return Add (String.Empty, text); @@ -4550,7 +4685,6 @@ namespace System.Windows.Forms Add (colHeader); return colHeader; } -#endif public virtual void AddRange (ColumnHeader [] values) { @@ -4568,6 +4702,10 @@ namespace System.Windows.Forms col.SetListView (null); list.Clear (); owner.ReorderColumns (new int [0], true); + + //UIA Framework event: Items cleared + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); + } public bool Contains (ColumnHeader value) @@ -4575,12 +4713,10 @@ namespace System.Windows.Forms return list.Contains (value); } -#if NET_2_0 public virtual bool ContainsKey (string key) { return IndexOfKey (key) != -1; } -#endif public IEnumerator GetEnumerator () { @@ -4642,7 +4778,6 @@ namespace System.Windows.Forms return list.IndexOf (value); } -#if NET_2_0 public virtual int IndexOfKey (string key) { if (key == null || key.Length == 0) @@ -4656,7 +4791,6 @@ namespace System.Windows.Forms return -1; } -#endif public void Insert (int index, ColumnHeader value) { @@ -4667,9 +4801,11 @@ namespace System.Windows.Forms list.Insert (index, value); owner.AddColumn (value, index, true); + + //UIA Framework event: Item added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); } -#if NET_2_0 public void Insert (int index, string text) { Insert (index, String.Empty, text); @@ -4707,16 +4843,10 @@ namespace System.Windows.Forms colHeader.ImageKey = imageKey; Insert (index, colHeader); } -#endif -#if NET_2_0 public void Insert (int index, string text, int width, HorizontalAlignment textAlign) { string str = text; -#else - public void Insert (int index, string str, int width, HorizontalAlignment textAlign) - { -#endif ColumnHeader colHeader = new ColumnHeader (this.owner, str, textAlign, width); this.Insert (index, colHeader); } @@ -4743,16 +4873,17 @@ namespace System.Windows.Forms column.InternalDisplayIndex = -1; owner.ReorderColumns (display_indices, true); + + //UIA Framework event: Item Removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, column)); } -#if NET_2_0 public virtual void RemoveByKey (string key) { int idx = IndexOfKey (key); if (idx != -1) RemoveAt (idx); } -#endif public virtual void RemoveAt (int index) { @@ -4767,16 +4898,44 @@ namespace System.Windows.Forms } // ColumnHeaderCollection -#if NET_2_0 [ListBindable (false)] -#endif public class ListViewItemCollection : IList, ICollection, IEnumerable { private readonly ArrayList list; private ListView owner; -#if NET_2_0 private ListViewGroup group; -#endif + + #region UIA Framework Events + //NOTE: + // We are using Reflection to add/remove internal events. + // Class ListViewProvider uses the events. + // + //Event used to generate UIA StructureChangedEvent + static object UIACollectionChangedEvent = new object (); + + internal event CollectionChangeEventHandler UIACollectionChanged { + add { + if (owner != null) + owner.Events.AddHandler (UIACollectionChangedEvent, value); + } + remove { + if (owner != null) + owner.Events.RemoveHandler (UIACollectionChangedEvent, value); + } + } + + internal void OnUIACollectionChangedEvent (CollectionChangeEventArgs args) + { + if (owner == null) + return; + + CollectionChangeEventHandler eh + = (CollectionChangeEventHandler) owner.Events [UIACollectionChangedEvent]; + if (eh != null) + eh (owner, args); + } + + #endregion UIA Framework Events // The collection can belong to a ListView (main) or to a ListViewGroup (sub-collection) // In the later case ListViewItem.ListView never gets modified @@ -4790,22 +4949,18 @@ namespace System.Windows.Forms } #endregion // Public Constructor -#if NET_2_0 internal ListViewItemCollection (ListView owner, ListViewGroup group) : this (owner) { this.group = group; is_main_collection = false; } -#endif #region Public Properties [Browsable (false)] public int Count { get { -#if NET_2_0 if (owner != null && owner.VirtualMode) return owner.VirtualListSize; -#endif return list.Count; } @@ -4815,38 +4970,22 @@ namespace System.Windows.Forms get { return false; } } -#if NET_2_0 public virtual ListViewItem this [int index] { -#else - public virtual ListViewItem this [int displayIndex] { -#endif get { -#if !NET_2_0 - int index = displayIndex; -#endif - if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException ("index"); -#if NET_2_0 if (owner != null && owner.VirtualMode) return RetrieveVirtualItemFromOwner (index); -#endif return (ListViewItem) list [index]; } set { -#if !NET_2_0 - int index = displayIndex; -#endif - if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException ("index"); -#if NET_2_0 if (owner != null && owner.VirtualMode) throw new InvalidOperationException (); -#endif if (list.Contains (value)) throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "value"); @@ -4856,21 +4995,26 @@ namespace System.Windows.Forms if (is_main_collection) value.Owner = owner; -#if NET_2_0 else { if (value.Group != null) value.Group.Items.Remove (value); value.SetGroup (group); } -#endif + + //UIA Framework event: Item Replaced + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, list [index])); list [index] = value; + CollectionChanged (true); + + //UIA Framework event: Item Replaced + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); + } } -#if NET_2_0 public virtual ListViewItem this [string key] { get { int idx = IndexOfKey (key); @@ -4880,7 +5024,6 @@ namespace System.Windows.Forms return this [idx]; } } -#endif bool ICollection.IsSynchronized { get { return true; } @@ -4897,11 +5040,17 @@ namespace System.Windows.Forms object IList.this [int index] { get { return this [index]; } set { + //UIA Framework event: Item Replaced + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, this [index])); + if (value is ListViewItem) this [index] = (ListViewItem) value; else this [index] = new ListViewItem (value.ToString ()); + OnChange (); + //UIA Framework event: Item Replaced + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); } } #endregion // Public Properties @@ -4909,13 +5058,17 @@ namespace System.Windows.Forms #region Public Methods public virtual ListViewItem Add (ListViewItem value) { -#if NET_2_0 if (owner != null && owner.VirtualMode) throw new InvalidOperationException (); -#endif AddItem (value); - CollectionChanged (true); + + // Item is ignored until it has been added to the ListView + if (is_main_collection || value.ListView != null) + CollectionChanged (true); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, value)); return value; } @@ -4932,7 +5085,6 @@ namespace System.Windows.Forms return this.Add (item); } -#if NET_2_0 public virtual ListViewItem Add (string text, string imageKey) { ListViewItem item = new ListViewItem (text, imageKey); @@ -4952,30 +5104,28 @@ namespace System.Windows.Forms item.Name = key; return this.Add (item); } -#endif -#if NET_2_0 public void AddRange (ListViewItem [] items) { -#else - public void AddRange (ListViewItem [] values) - { - ListViewItem [] items = values; -#endif if (items == null) throw new ArgumentNullException ("Argument cannot be null!", "items"); -#if NET_2_0 if (owner != null && owner.VirtualMode) throw new InvalidOperationException (); -#endif - foreach (ListViewItem item in items) + owner.BeginUpdate (); + + foreach (ListViewItem item in items) { AddItem (item); + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item)); + } + + owner.EndUpdate (); + CollectionChanged (true); } -#if NET_2_0 public void AddRange (ListViewItemCollection items) { if (items == null) @@ -4985,32 +5135,55 @@ namespace System.Windows.Forms items.CopyTo (itemArray,0); this.AddRange (itemArray); } -#endif public virtual void Clear () { -#if NET_2_0 if (owner != null && owner.VirtualMode) throw new InvalidOperationException (); -#endif if (is_main_collection && owner != null) { owner.SetFocusedItem (-1); owner.h_scroll.Value = owner.v_scroll.Value = 0; - + + // first remove any item in the groups that *are* part of this LV too + foreach (ListViewGroup group in owner.groups) + group.Items.ClearItemsWithSameListView (); + foreach (ListViewItem item in list) { owner.item_control.CancelEdit (item); item.Owner = null; } - } -#if NET_2_0 else foreach (ListViewItem item in list) item.SetGroup (null); -#endif list.Clear (); CollectionChanged (false); + + //UIA Framework event: Items Removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Refresh, null)); + + } + + // This method is intended to be used from ListViewGroup.Items, not from ListView.Items, + // added for performance reasons (avoid calling manually Remove for every item on ListViewGroup.Items) + void ClearItemsWithSameListView () + { + if (is_main_collection) + return; + + int counter = list.Count - 1; + while (counter >= 0) { + ListViewItem item = list [counter] as ListViewItem; + + // remove only if the items in group have being added to the ListView too + if (item.ListView == group.ListView) { + list.RemoveAt (counter); + item.SetGroup (null); + } + + counter--; + } } public bool Contains (ListViewItem item) @@ -5018,19 +5191,16 @@ namespace System.Windows.Forms return IndexOf (item) != -1; } -#if NET_2_0 public virtual bool ContainsKey (string key) { return IndexOfKey (key) != -1; } -#endif public void CopyTo (Array dest, int index) { list.CopyTo (dest, index); } -#if NET_2_0 public ListViewItem [] Find (string key, bool searchAllSubItems) { if (key == null) @@ -5049,16 +5219,15 @@ namespace System.Windows.Forms return retval; } -#endif public IEnumerator GetEnumerator () { -#if NET_2_0 if (owner != null && owner.VirtualMode) throw new InvalidOperationException (); -#endif - - return list.GetEnumerator (); + + // This enumerator makes a copy of the collection so + // it can be deleted from in a foreach + return new Control.ControlCollection.ControlCollectionEnumerator (list); } int IList.Add (object item) @@ -5066,10 +5235,8 @@ namespace System.Windows.Forms int result; ListViewItem li; -#if NET_2_0 if (owner != null && owner.VirtualMode) throw new InvalidOperationException (); -#endif if (item is ListViewItem) { li = (ListViewItem) item; @@ -5083,9 +5250,14 @@ namespace System.Windows.Forms li = new ListViewItem (item.ToString ()); li.Owner = owner; + + result = list.Add (li); CollectionChanged (true); + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, li)); + return result; } @@ -5105,6 +5277,9 @@ namespace System.Windows.Forms this.Insert (index, (ListViewItem) item); else this.Insert (index, item.ToString ()); + + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, this [index])); } void IList.Remove (object item) @@ -5114,7 +5289,6 @@ namespace System.Windows.Forms public int IndexOf (ListViewItem item) { -#if NET_2_0 if (owner != null && owner.VirtualMode) { for (int i = 0; i < Count; i++) if (RetrieveVirtualItemFromOwner (i) == item) @@ -5122,12 +5296,10 @@ namespace System.Windows.Forms return -1; } -#endif return list.IndexOf (item); } -#if NET_2_0 public virtual int IndexOfKey (string key) { if (key == null || key.Length == 0) @@ -5141,17 +5313,14 @@ namespace System.Windows.Forms return -1; } -#endif public ListViewItem Insert (int index, ListViewItem item) { if (index < 0 || index > list.Count) throw new ArgumentOutOfRangeException ("index"); -#if NET_2_0 if (owner != null && owner.VirtualMode) throw new InvalidOperationException (); -#endif if (list.Contains (item)) throw new ArgumentException ("An item cannot be added more than once. To add an item again, you need to clone it.", "item"); @@ -5161,17 +5330,24 @@ namespace System.Windows.Forms if (is_main_collection) item.Owner = owner; -#if NET_2_0 else { if (item.Group != null) item.Group.Items.Remove (item); item.SetGroup (group); } -#endif list.Insert (index, item); - CollectionChanged (true); + + if (is_main_collection || item.ListView != null) + CollectionChanged (true); + + // force an update of the selected info if the new item is selected. + if (item.Selected) + item.SetSelectedCore (true); + //UIA Framework event: Item Added + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Add, item)); + return item; } @@ -5185,7 +5361,6 @@ namespace System.Windows.Forms return this.Insert (index, new ListViewItem (text, imageIndex)); } -#if NET_2_0 public ListViewItem Insert (int index, string text, string imageKey) { ListViewItem lvi = new ListViewItem (text, imageKey); @@ -5205,14 +5380,11 @@ namespace System.Windows.Forms lvi.Name = key; return Insert (index, lvi); } -#endif public virtual void Remove (ListViewItem item) { -#if NET_2_0 if (owner != null && owner.VirtualMode) throw new InvalidOperationException (); -#endif int idx = list.IndexOf (item); if (idx != -1) @@ -5224,18 +5396,17 @@ namespace System.Windows.Forms if (index < 0 || index >= Count) throw new ArgumentOutOfRangeException ("index"); -#if NET_2_0 if (owner != null && owner.VirtualMode) throw new InvalidOperationException (); -#endif ListViewItem item = (ListViewItem) list [index]; bool selection_changed = false; if (is_main_collection && owner != null) { - if (item.Focused && index + 1 == Count) // Last item - owner.SetFocusedItem (index == 0 ? -1 : index - 1); + int display_index = item.DisplayIndex; + if (item.Focused && display_index + 1 == Count) // Last item + owner.SetFocusedItem (display_index == 0 ? -1 : display_index - 1); selection_changed = owner.SelectedIndices.Contains (index); owner.item_control.CancelEdit (item); @@ -5243,26 +5414,28 @@ namespace System.Windows.Forms list.RemoveAt (index); - if (is_main_collection) + if (is_main_collection) { item.Owner = null; -#if NET_2_0 - else + if (item.Group != null) + item.Group.Items.Remove (item); + } else item.SetGroup (null); -#endif CollectionChanged (false); if (selection_changed && owner != null) owner.OnSelectedIndexChanged (EventArgs.Empty); + + + //UIA Framework event: Item Removed + OnUIACollectionChangedEvent (new CollectionChangeEventArgs (CollectionChangeAction.Remove, item)); } -#if NET_2_0 public virtual void RemoveByKey (string key) { int idx = IndexOfKey (key); if (idx != -1) RemoveAt (idx); } -#endif #endregion // Public Methods @@ -5275,7 +5448,6 @@ namespace System.Windows.Forms } } -#if NET_2_0 internal ListViewGroup Group { get { return group; @@ -5284,7 +5456,6 @@ namespace System.Windows.Forms group = value; } } -#endif void AddItem (ListViewItem value) { @@ -5295,30 +5466,31 @@ namespace System.Windows.Forms throw new ArgumentException ("Cannot add or insert the item '" + value.Text + "' in more than one place. You must first remove it from its current location or clone it.", "value"); if (is_main_collection) value.Owner = owner; -#if NET_2_0 else { if (value.Group != null) value.Group.Items.Remove (value); value.SetGroup (group); } -#endif list.Add (value); + + // force an update of the selected info if the new item is selected. + if (value.Selected) + value.SetSelectedCore (true); } void CollectionChanged (bool sort) { if (owner != null) { - if (sort) - owner.Sort (false); + if (sort) + owner.Sort (false); OnChange (); owner.Redraw (true); } } -#if NET_2_0 ListViewItem RetrieveVirtualItemFromOwner (int displayIndex) { RetrieveVirtualItemEventArgs args = new RetrieveVirtualItemEventArgs (displayIndex); @@ -5327,10 +5499,10 @@ namespace System.Windows.Forms ListViewItem retval = args.Item; retval.Owner = owner; retval.DisplayIndex = displayIndex; + retval.Layout (); return retval; } -#endif internal event CollectionChangedHandler Changed; @@ -5353,9 +5525,7 @@ namespace System.Windows.Forms // // In virtual mode, SelectedIndexCollection directly saves the selection // information, instead of getting it from Items, making List read-and-write -#if NET_2_0 [ListBindable (false)] -#endif public class SelectedIndexCollection : IList, ICollection, IEnumerable { private readonly ListView owner; @@ -5373,7 +5543,7 @@ namespace System.Windows.Forms [Browsable (false)] public int Count { get { - if (!owner.IsHandleCreated) + if (!owner.is_selection_available) return 0; return List.Count; @@ -5382,17 +5552,13 @@ namespace System.Windows.Forms public bool IsReadOnly { get { -#if NET_2_0 return false; -#else - return true; -#endif } } public int this [int index] { get { - if (!owner.IsHandleCreated || index < 0 || index >= List.Count) + if (!owner.is_selection_available || index < 0 || index >= List.Count) throw new ArgumentOutOfRangeException ("index"); return (int) List [index]; @@ -5409,11 +5575,7 @@ namespace System.Windows.Forms bool IList.IsFixedSize { get { -#if NET_2_0 return false; -#else - return true; -#endif } } @@ -5424,32 +5586,25 @@ namespace System.Windows.Forms #endregion // Public Properties #region Public Methods -#if NET_2_0 public int Add (int itemIndex) { if (itemIndex < 0 || itemIndex >= owner.Items.Count) throw new ArgumentOutOfRangeException ("index"); - if (owner.virtual_mode && !owner.IsHandleCreated) + if (owner.virtual_mode && !owner.is_selection_available) return -1; owner.Items [itemIndex].Selected = true; - if (!owner.IsHandleCreated) + if (!owner.is_selection_available) return 0; return List.Count; } -#endif -#if NET_2_0 - public -#else - internal -#endif - void Clear () + public void Clear () { - if (!owner.IsHandleCreated) + if (!owner.is_selection_available) return; int [] indexes = (int []) List.ToArray (typeof (int)); @@ -5513,13 +5668,12 @@ namespace System.Windows.Forms public int IndexOf (int selectedIndex) { - if (!owner.IsHandleCreated) + if (!owner.is_selection_available) return -1; return List.IndexOf (selectedIndex); } -#if NET_2_0 public void Remove (int itemIndex) { if (itemIndex < 0 || itemIndex >= owner.Items.Count) @@ -5527,16 +5681,13 @@ namespace System.Windows.Forms owner.Items [itemIndex].Selected = false; } -#endif #endregion // Public Methods internal ArrayList List { get { if (list == null) { list = new ArrayList (); -#if NET_2_0 if (!owner.VirtualMode) -#endif for (int i = 0; i < owner.Items.Count; i++) { if (owner.Items [i].Selected) list.Add (i); @@ -5557,7 +5708,6 @@ namespace System.Windows.Forms Reset (); } -#if NET_2_0 internal void RemoveIndex (int index) { int idx = List.BinarySearch (index); @@ -5585,13 +5735,10 @@ namespace System.Windows.Forms List.Insert (iMin, index); } -#endif } // SelectedIndexCollection -#if NET_2_0 [ListBindable (false)] -#endif public class SelectedListViewItemCollection : IList, ICollection, IEnumerable { private readonly ListView owner; @@ -5617,7 +5764,7 @@ namespace System.Windows.Forms public ListViewItem this [int index] { get { - if (!owner.IsHandleCreated || index < 0 || index >= Count) + if (!owner.is_selection_available || index < 0 || index >= Count) throw new ArgumentOutOfRangeException ("index"); int item_index = owner.SelectedIndices [index]; @@ -5625,7 +5772,6 @@ namespace System.Windows.Forms } } -#if NET_2_0 public virtual ListViewItem this [string key] { get { int idx = IndexOfKey (key); @@ -5635,7 +5781,6 @@ namespace System.Windows.Forms return this [idx]; } } -#endif bool ICollection.IsSynchronized { get { return false; } @@ -5666,16 +5811,14 @@ namespace System.Windows.Forms return IndexOf (item) != -1; } -#if NET_2_0 public virtual bool ContainsKey (string key) { return IndexOfKey (key) != -1; } -#endif public void CopyTo (Array dest, int index) { - if (!owner.IsHandleCreated) + if (!owner.is_selection_available) return; if (index > Count) // Throws ArgumentException instead of IOOR exception throw new ArgumentException ("index"); @@ -5686,7 +5829,7 @@ namespace System.Windows.Forms public IEnumerator GetEnumerator () { - if (!owner.IsHandleCreated) + if (!owner.is_selection_available) return (new ListViewItem [0]).GetEnumerator (); ListViewItem [] items = new ListViewItem [Count]; @@ -5732,7 +5875,7 @@ namespace System.Windows.Forms public int IndexOf (ListViewItem item) { - if (!owner.IsHandleCreated) + if (!owner.is_selection_available) return -1; for (int i = 0; i < Count; i++) @@ -5742,10 +5885,9 @@ namespace System.Windows.Forms return -1; } -#if NET_2_0 public virtual int IndexOfKey (string key) { - if (!owner.IsHandleCreated || key == null || key.Length == 0) + if (!owner.is_selection_available || key == null || key.Length == 0) return -1; for (int i = 0; i < Count; i++) { @@ -5756,7 +5898,6 @@ namespace System.Windows.Forms return -1; } -#endif #endregion // Public Methods } // SelectedListViewItemCollection @@ -5796,7 +5937,6 @@ namespace System.Windows.Forms } #endregion // Subclasses -#if NET_2_0 protected override void OnResize (EventArgs e) { base.OnResize (e); @@ -5876,18 +6016,131 @@ namespace System.Windows.Forms cwceh (this, changing); return !changing.Cancel; } -#else - // - // 1.0 profile based implementation - // - bool CanProceedWithResize (ColumnHeader col, int width) + + internal void RaiseColumnWidthChanged (ColumnHeader column) { - return true; + int index = Columns.IndexOf (column); + RaiseColumnWidthChanged (index); } - void RaiseColumnWidthChanged (int resize_column) + + #region UIA Framework: Methods, Properties and Events + + static object UIALabelEditChangedEvent = new object (); + static object UIAShowGroupsChangedEvent = new object (); + static object UIAMultiSelectChangedEvent = new object (); + static object UIAViewChangedEvent = new object (); + static object UIACheckBoxesChangedEvent = new object (); + static object UIAFocusedItemChangedEvent = new object (); + + internal Rectangle UIAHeaderControl { + get { return header_control.Bounds; } + } + + internal int UIAColumns { + get { return cols; } + } + + internal int UIARows { + get { return rows; } + } + + internal ListViewGroup UIADefaultListViewGroup + { + get { return groups.DefaultGroup; } + } + + internal ScrollBar UIAHScrollBar { + get { return h_scroll; } + } + + internal ScrollBar UIAVScrollBar { + get { return v_scroll; } + } + + internal event EventHandler UIAShowGroupsChanged { + add { Events.AddHandler (UIAShowGroupsChangedEvent, value); } + remove { Events.RemoveHandler (UIAShowGroupsChangedEvent, value); } + } + + internal event EventHandler UIACheckBoxesChanged { + add { Events.AddHandler (UIACheckBoxesChangedEvent, value); } + remove { Events.RemoveHandler (UIACheckBoxesChangedEvent, value); } + } + + internal event EventHandler UIAMultiSelectChanged { + add { Events.AddHandler (UIAMultiSelectChangedEvent, value); } + remove { Events.RemoveHandler (UIAMultiSelectChangedEvent, value); } + } + + internal event EventHandler UIALabelEditChanged { + add { Events.AddHandler (UIALabelEditChangedEvent, value); } + remove { Events.RemoveHandler (UIALabelEditChangedEvent, value); } + } + + internal event EventHandler UIAViewChanged { + add { Events.AddHandler (UIAViewChangedEvent, value); } + remove { Events.RemoveHandler (UIAViewChangedEvent, value); } + } + + internal event EventHandler UIAFocusedItemChanged { + add { Events.AddHandler (UIAFocusedItemChangedEvent, value); } + remove { Events.RemoveHandler (UIAFocusedItemChangedEvent, value); } + } + + internal Rectangle UIAGetHeaderBounds (ListViewGroup group) { + return group.HeaderBounds; + } + + internal int UIAItemsLocationLength + { + get { return items_location.Length; } + } + + private void OnUIACheckBoxesChanged () + { + EventHandler eh = (EventHandler) Events [UIACheckBoxesChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); } -#endif + + private void OnUIAShowGroupsChanged () + { + EventHandler eh = (EventHandler) Events [UIAShowGroupsChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void OnUIAMultiSelectChanged () + { + EventHandler eh = (EventHandler) Events [UIAMultiSelectChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void OnUIALabelEditChanged () + { + EventHandler eh = (EventHandler) Events [UIALabelEditChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + private void OnUIAViewChanged () + { + EventHandler eh = (EventHandler) Events [UIAViewChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + internal void OnUIAFocusedItemChanged () + { + EventHandler eh = (EventHandler) Events [UIAFocusedItemChangedEvent]; + if (eh != null) + eh (this, EventArgs.Empty); + } + + #endregion // UIA Framework: Methods, Properties and Events + } }