// Authors:
// Ravindra Kumar (rkumar@novell.com)
// Jordi Mas i Hernandez, jordi@ximian.com
+// Mike Kestner (mkestner@novell.com)
//
// TODO:
-// - Item text editing
-// - Column resizing/reodering
// - Feedback for item activation, change in cursor types as mouse moves.
-// - HideSelection
// - LabelEdit
-// - Manual column resizing
// - Drag and drop
using System.ComponentModel.Design;
using System.Drawing;
using System.Runtime.InteropServices;
+using System.Globalization;
namespace System.Windows.Forms
{
private bool check_boxes = false;
private CheckedIndexCollection checked_indices;
private CheckedListViewItemCollection checked_items;
- private ColumnHeader clicked_column;
- private ListViewItem clicked_item;
- private ListViewItem last_clicked_item;
private ColumnHeaderCollection columns;
- private bool ctrl_pressed;
- private bool shift_pressed;
internal ListViewItem focused_item;
private bool full_row_select = false;
private bool grid_lines = false;
private int layout_wd; // We might draw more than our client area
private int layout_ht; // therefore we need to have these two.
//private TextBox editor; // Used for editing an item text
+ HeaderControl header_control;
+ internal ItemControl item_control;
internal ScrollBar h_scroll; // used for scrolling horizontally
internal ScrollBar v_scroll; // used for scrolling vertically
internal int h_marker; // Position markers for scrolling
internal int v_marker;
- internal Rectangle client_area; // ClientRectangle - scrollbars
+ private int keysearch_tickcnt;
+ private string keysearch_text;
+ static private readonly int keysearch_keydelay = 1000;
+ private int[] reordered_column_indices;
// internal variables
internal ImageList large_image_list;
[Browsable (false)]
[EditorBrowsable (EditorBrowsableState.Never)]
- public new event EventHandler BackgroundImageChanged;
+ public new event EventHandler BackgroundImageChanged {
+ add { base.BackgroundImageChanged += value; }
+ remove { base.BackgroundImageChanged -= value; }
+ }
public event LabelEditEventHandler BeforeLabelEdit;
public event ColumnClickEventHandler ColumnClick;
[Browsable (false)]
[EditorBrowsable (EditorBrowsableState.Never)]
- public new event PaintEventHandler Paint;
+ public new event PaintEventHandler Paint {
+ add { base.Paint += value; }
+ remove { base.Paint -= value; }
+ }
public event EventHandler SelectedIndexChanged;
[Browsable (false)]
[EditorBrowsable (EditorBrowsableState.Never)]
- public new event EventHandler TextChanged;
+ public new event EventHandler TextChanged {
+ add { base.TextChanged += value; }
+ remove { base.TextChanged -= value; }
+ }
+
#endregion // Events
#region Public Constructors
border_style = BorderStyle.Fixed3D;
- // we are mostly scrollable
+ header_control = new HeaderControl (this);
+ header_control.Visible = false;
+ Controls.AddImplicit (header_control);
+
+ item_control = new ItemControl (this);
+ Controls.AddImplicit (item_control);
+
h_scroll = new HScrollBar ();
+ Controls.AddImplicit (this.h_scroll);
+
v_scroll = new VScrollBar ();
+ Controls.AddImplicit (this.v_scroll);
+
h_marker = v_marker = 0;
+ keysearch_tickcnt = 0;
// scroll bars are disabled initially
h_scroll.Visible = false;
v_scroll.ValueChanged += new EventHandler(VerticalScroller);
// event handlers
- base.DoubleClick += new EventHandler(ListView_DoubleClick);
base.KeyDown += new KeyEventHandler(ListView_KeyDown);
- base.KeyUp += new KeyEventHandler(ListView_KeyUp);
- base.MouseDown += new MouseEventHandler(ListView_MouseDown);
- base.MouseHover += new EventHandler(ListView_MouseHover);
- base.MouseUp += new MouseEventHandler(ListView_MouseUp);
- base.MouseMove += new MouseEventHandler(ListView_MouseMove);
- base.Paint += new PaintEventHandler (ListView_Paint);
SizeChanged += new EventHandler (ListView_SizeChanged);
+ GotFocus += new EventHandler (FocusChanged);
+ LostFocus += new EventHandler (FocusChanged);
+ MouseWheel += new MouseEventHandler(ListView_MouseWheel);
this.SetStyle (ControlStyles.UserPaint | ControlStyles.StandardClick, false);
}
}
}
- internal bool CanMultiselect {
+ bool multiselecting;
+
+ bool CanMultiselect {
get {
- if (this.multiselect &&
- (this.ctrl_pressed || this.shift_pressed))
+ if (multiselecting)
+ return true;
+ else if (multiselect && (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0)
return true;
else
return false;
}
}
+
#endregion // Private Internal Properties
#region Protected Properties
[DefaultValue (false)]
public bool AllowColumnReorder {
get { return allow_column_reorder; }
- set {
- if (this.allow_column_reorder != value) {
- allow_column_reorder = value;
- // column reorder does not matter in Details view
- if (this.view != View.Details)
- this.Redraw (true);
- }
- }
+ set { allow_column_reorder = value; }
}
[DefaultValue (true)]
return;
background_image = value;
- if (BackgroundImageChanged != null)
- BackgroundImageChanged (this, new EventArgs ());
+ OnBackgroundImageChanged (EventArgs.Empty);
}
}
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);
}
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public ListViewItem FocusedItem {
- get { return focused_item; }
+ get {
+ return focused_item;
+ }
}
public override Color ForeColor {
public ColumnHeaderStyle HeaderStyle {
get { return header_style; }
set {
- if (value != ColumnHeaderStyle.Clickable && value != ColumnHeaderStyle.Nonclickable &&
- value != ColumnHeaderStyle.None) {
+ if (header_style == value)
+ return;
+
+ switch (value) {
+ case ColumnHeaderStyle.Clickable:
+ case ColumnHeaderStyle.Nonclickable:
+ case ColumnHeaderStyle.None:
+ break;
+ default:
throw new InvalidEnumArgumentException (string.Format
("Enum argument value '{0}' is not valid for ColumnHeaderStyle", value));
}
- if (header_style != value) {
- header_style = value;
- // header style matters only in Details view
- if (this.view == View.Details)
- this.Redraw (false);
- }
+ header_style = value;
+ if (view == View.Details)
+ Redraw (true);
}
}
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public IComparer ListViewItemSorter {
- get { return item_sorter; }
- set { item_sorter = value; }
+ get {
+ if (View != View.SmallIcon && View != View.LargeIcon && item_sorter is ItemComparer)
+ return null;
+ return item_sorter;
+ }
+ set {
+ if (item_sorter != value) {
+ item_sorter = value;
+ Sort ();
+ }
+ }
}
[DefaultValue (true)]
get { return selected_items; }
}
+#if NET_2_0
+ [MonoTODO("Implement")]
+ public bool ShowGroups {
+ get {
+ return false;
+ }
+
+ set {
+ }
+ }
+#endif
+
[DefaultValue (null)]
public ImageList SmallImageList {
get { return small_image_list; }
public SortOrder Sorting {
get { return sort_order; }
set {
- if (value != SortOrder.Ascending && value != SortOrder.Descending &&
- value != SortOrder.None) {
- throw new InvalidEnumArgumentException (string.Format
- ("Enum argument value '{0}' is not valid for Sorting", value));
+ if (!Enum.IsDefined (typeof (SortOrder), value)) {
+ throw new InvalidEnumArgumentException ("value", (int) value,
+ typeof (SortOrder));
}
- if (sort_order != value) {
- sort_order = value;
+ if (sort_order == value)
+ return;
+
+ sort_order = value;
+
+ 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 ();
}
}
}
text = value;
this.Redraw (true);
- if (TextChanged != null)
- TextChanged (this, new EventArgs ());
+ OnTextChanged (EventArgs.Empty);
}
}
// do a hit test for the scrolled position
else {
foreach (ListViewItem item in this.items) {
- if (item.EntireRect.X >= h_marker && item.EntireRect.Y >= v_marker)
+ if (item.Bounds.X >= 0 && item.Bounds.Y >= 0)
return item;
}
return null;
}
}
+#if NET_2_0
+ [MonoTODO("Implement")]
+ public bool UseCompatibleStateImageBehavior {
+ get {
+ return false;
+ }
+
+ set {
+ }
+ }
+#endif
+
[DefaultValue (View.LargeIcon)]
public View View {
get { return view; }
set {
- if (value != View.Details && value != View.LargeIcon &&
- value != View.List && value != View.SmallIcon ) {
- throw new InvalidEnumArgumentException (string.Format
- ("Enum argument value '{0}' is not valid for View", value));
- }
-
+ if (!Enum.IsDefined (typeof (View), value))
+ throw new InvalidEnumArgumentException ("value", (int) value,
+ 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
+
+ h_scroll.Value = v_scroll.Value = 0;
view = value;
Redraw (true);
}
return 0;
foreach (ListViewItem item in this.items) {
- if (item.EntireRect.X + item.EntireRect.Width >= h_marker
- && item.EntireRect.Y + item.EntireRect.Height >= v_marker)
+ if (item.Bounds.Right >= 0 && item.Bounds.Bottom >= 0)
return item.Index;
}
return 0;
}
- internal int LastItemIndex {
+ internal int LastVisibleIndex {
get {
- for (int i = FirstVisibleIndex; i < Items.Count; i++) {
- if (Items[i].EntireRect.Y > v_marker + ClientRectangle.Bottom)
- return i -1;
+ for (int i = FirstVisibleIndex; i < Items.Count; i++) {
+ if (View == View.List || Alignment == ListViewAlignment.Left) {
+ if (Items[i].Bounds.X > ClientRectangle.Right)
+ return i - 1;
+ } else {
+ if (Items[i].Bounds.Y > ClientRectangle.Bottom)
+ return i - 1;
+ }
}
return Items.Count - 1;
text_size.Height += 2;
}
+ private void Scroll (ScrollBar scrollbar, int delta)
+ {
+ if (delta == 0 || !scrollbar.Visible)
+ return;
+
+ int max;
+ if (scrollbar == h_scroll)
+ max = h_scroll.Maximum - item_control.Width;
+ else
+ max = v_scroll.Maximum - item_control.Height;
+
+ int val = scrollbar.Value + delta;
+ if (val > max)
+ val = max;
+ else if (val < scrollbar.Minimum)
+ val = scrollbar.Minimum;
+ scrollbar.Value = val;
+ }
+
private void CalculateScrollBars ()
{
- client_area = ClientRectangle;
+ Rectangle client_area = ClientRectangle;
if (!this.scrollable || this.items.Count <= 0) {
h_scroll.Visible = false;
v_scroll.Visible = false;
+ item_control.Location = new Point (0, header_control.Height);
+ item_control.Height = ClientRectangle.Width - header_control.Height;
+ item_control.Width = ClientRectangle.Width;
+ header_control.Width = ClientRectangle.Width;
return;
}
+ // Don't calculate if the view is not displayable
+ if (client_area.Height < 0 || client_area.Width < 0)
+ return;
+
// making a scroll bar visible might make
// other scroll bar visible
if (layout_wd > client_area.Right) {
h_scroll.Visible = true;
- if ((layout_ht + h_scroll.Height) > client_area.Bottom) {
+ if ((layout_ht + h_scroll.Height) > client_area.Bottom)
v_scroll.Visible = true;
- }
+ else
+ v_scroll.Visible = false;
} else if (layout_ht > client_area.Bottom) {
v_scroll.Visible = true;
if ((layout_wd + v_scroll.Width) > client_area.Right)
h_scroll.Visible = true;
- }
+ else
+ h_scroll.Visible = false;
+ } else {
+ h_scroll.Visible = false;
+ v_scroll.Visible = false;
+ }
+
+ item_control.Height = ClientRectangle.Height - header_control.Height;
if (h_scroll.Visible) {
h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
h_scroll.LargeChange = client_area.Width;
h_scroll.SmallChange = Font.Height;
- client_area.Height -= h_scroll.Height;
+ item_control.Height -= h_scroll.Height;
}
- // vertical scrollbar
+ if (header_control.Visible)
+ header_control.Width = ClientRectangle.Width;
+ item_control.Width = ClientRectangle.Width;
+
if (v_scroll.Visible) {
v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
v_scroll.Minimum = 0;
v_scroll.LargeChange = client_area.Height;
v_scroll.SmallChange = Font.Height;
- client_area.Width -= v_scroll.Width;
+ if (header_control.Visible)
+ header_control.Width -= v_scroll.Width;
+ item_control.Width -= v_scroll.Width;
}
}
-
- // Sets the location of every item on
- // the ListView as per the view
- private void CalculateListView (ListViewAlignment align)
+ ColumnHeader GetReorderedColumn (int index)
{
- int current_pos_x = 0; // our x-position marker
- int current_pos_y = 0; // our y-position marker
- int item_ht;
- int item_wd;
- int max; // max x_pos or y_pos depending on the alignment
- int current = 0; // current row or column
- int vertical_spacing = ThemeEngine.Current.ListViewVerticalSpacing;
- int horizontal_spacing = ThemeEngine.Current.ListViewHorizontalSpacing;
+ if (reordered_column_indices == null)
+ return Columns [index];
+ else
+ return Columns [reordered_column_indices [index]];
+ }
- CalcTextSize ();
+ void ReorderColumn (ColumnHeader col, int index)
+ {
+ if (reordered_column_indices == null) {
+ reordered_column_indices = new int [Columns.Count];
+ for (int i = 0; i < Columns.Count; i++)
+ reordered_column_indices [i] = i;
+ }
- switch (view) {
+ if (reordered_column_indices [index] == col.Index)
+ return;
- case View.Details:
- // ColumnHeaders are not drawn if headerstyle is none
- int ht = (this.header_style == ColumnHeaderStyle.None) ?
- 0 : this.Font.Height + 3;
-
- if (columns.Count > 0) {
- foreach (ColumnHeader col in columns) {
- col.X = current_pos_x;
- col.Y = current_pos_y;
- col.CalcColumnHeader ();
- current_pos_x += col.Wd;
+ int[] curr = reordered_column_indices;
+ int[] result = new int [Columns.Count];
+ int curr_idx = 0;
+ for (int i = 0; i < Columns.Count; i++) {
+ if (curr_idx < Columns.Count && curr [curr_idx] == col.Index)
+ curr_idx++;
+
+ if (i == index)
+ result [i] = col.Index;
+ else
+ result [i] = curr [curr_idx++];
+ }
+
+ reordered_column_indices = result;
+ LayoutDetails ();
+ header_control.Invalidate ();
+ item_control.Invalidate ();
+ }
+
+ Size LargeIconItemSize {
+ get {
+ int image_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
+ int image_h = LargeImageList == null ? 2 : LargeImageList.ImageSize.Height;
+ int w = CheckBoxSize.Width + 2 + Math.Max (text_size.Width, image_w);
+ int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, image_h);
+ return new Size (w, h);
+ }
+ }
+
+ Size SmallIconItemSize {
+ get {
+ int image_w = SmallImageList == null ? 0 : SmallImageList.ImageSize.Width;
+ int image_h = SmallImageList == null ? 0 : SmallImageList.ImageSize.Height;
+ int w = text_size.Width + 2 + CheckBoxSize.Width + image_w;
+ int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, image_h));
+ return new Size (w, h);
+ }
+ }
+
+ int rows;
+ int cols;
+ ListViewItem[,] item_matrix;
+
+ void LayoutIcons (bool large_icons, bool left_aligned, int x_spacing, int y_spacing)
+ {
+ header_control.Visible = false;
+ header_control.Size = Size.Empty;
+ item_control.Visible = true;
+ item_control.Location = Point.Empty;
+
+ if (items.Count == 0)
+ return;
+
+ Size sz = large_icons ? LargeIconItemSize : SmallIconItemSize;
+
+ Rectangle area = ClientRectangle;
+
+ if (left_aligned) {
+ rows = (int) Math.Floor ((double)(area.Height - h_scroll.Height + y_spacing) / (double)(sz.Height + y_spacing));
+ if (rows <= 0)
+ rows = 1;
+ cols = (int) Math.Ceiling ((double)items.Count / (double)rows);
+ } else {
+ cols = (int) Math.Floor ((double)(area.Width - v_scroll.Width + x_spacing) / (double)(sz.Width + x_spacing));
+ if (cols <= 0)
+ cols = 1;
+ rows = (int) Math.Ceiling ((double)items.Count / (double)cols);
+ }
+
+ layout_ht = rows * (sz.Height + y_spacing) - y_spacing;
+ layout_wd = cols * (sz.Width + x_spacing) - x_spacing;
+ item_matrix = new ListViewItem [rows, cols];
+ int row = 0;
+ int col = 0;
+ foreach (ListViewItem item in items) {
+ int x = col * (sz.Width + x_spacing);
+ int y = row * (sz.Height + y_spacing);
+ item.Location = new Point (x, y);
+ item.Layout ();
+ item.row = row;
+ item.col = col;
+ item_matrix [row, col] = item;
+ if (left_aligned) {
+ if (++row == rows) {
+ row = 0;
+ col++;
}
- this.layout_wd = current_pos_x;
- }
- // set the position marker for placing items
- // vertically down
- current_pos_y = ht;
-
- if (items.Count > 0) {
- foreach (ListViewItem item in items) {
- item.location.X = 0;
- item.location.Y = current_pos_y;
- item.CalcListViewItem ();
- current_pos_y += item.EntireRect.Height;
+ } else {
+ if (++col == cols) {
+ col = 0;
+ row++;
}
- this.layout_ht = current_pos_y;
+ }
+ }
+
+ item_control.Size = new Size (layout_wd, layout_ht);
+ }
+
+ void LayoutHeader ()
+ {
+ int x = 0;
+ for (int i = 0; i < Columns.Count; i++) {
+ ColumnHeader col = GetReorderedColumn (i);
+ col.X = x;
+ col.Y = 0;
+ col.CalcColumnHeader ();
+ x += col.Wd;
+ }
+
+ if (x < ClientRectangle.Width)
+ x = ClientRectangle.Width;
+
+ if (header_style == ColumnHeaderStyle.None) {
+ header_control.Visible = false;
+ header_control.Size = Size.Empty;
+ } else {
+ header_control.Width = x;
+ header_control.Height = columns [0].Ht;
+ header_control.Visible = true;
+ }
+ }
+
+ void LayoutDetails ()
+ {
+ if (columns.Count == 0) {
+ header_control.Visible = false;
+ item_control.Visible = false;
+ return;
+ }
+
+ LayoutHeader ();
- // some space for bottom gridline
- if (this.grid_lines)
- this.layout_ht += 2;
+ item_control.Visible = true;
+ item_control.Location = new Point (0, header_control.Height);
+
+ int y = 0;
+ if (items.Count > 0) {
+ foreach (ListViewItem item in items) {
+ item.Layout ();
+ item.Location = new Point (0, y);
+ y += item.Bounds.Height + 2;
}
+
+ // some space for bottom gridline
+ if (grid_lines)
+ y += 2;
+ }
+
+ layout_wd = Math.Max (header_control.Width, item_control.Width);
+ layout_ht = y + header_control.Height;
+ }
+
+ private void CalculateListView (ListViewAlignment align)
+ {
+ CalcTextSize ();
+
+ switch (view) {
+ case View.Details:
+ LayoutDetails ();
break;
case View.SmallIcon:
- vertical_spacing = 0;
- horizontal_spacing = 0;
- goto case View.LargeIcon;
+ LayoutIcons (false, alignment == ListViewAlignment.Left, 4, 2);
+ break;
case View.LargeIcon:
- if (items.Count > 0) {
- items [0].CalcListViewItem ();
- item_ht = items [0].EntireRect.Height;
- item_wd = items [0].EntireRect.Width;
-
- // top (default) and snaptogrid alignments are handled same way
- if (align == ListViewAlignment.Left) {
- max = client_area.Height;
- foreach (ListViewItem item in items) {
- item.location.X = current_pos_x +
- horizontal_spacing;
- item.location.Y = 0;
- item.CalcListViewItem ();
- current_pos_y += item_ht;
-
- current ++; // just to know about the last element
- // we just did the last item
- if (current == items.Count) {
- if (max < current_pos_y)
- max = current_pos_y;
- current_pos_x = item.EntireRect.Right;
- break;
- }
- else {
- // is there enough space for another row ?
- if ((current_pos_y + vertical_spacing
- + item_ht) <= client_area.Height)
- current_pos_y += vertical_spacing;
- else {
- // start another column
- // make current_pos_y as the
- // max value and reset
- // current_pos_y value.
- max = current_pos_y;
- current_pos_x += item_wd;
- current_pos_y = 0;
- }
- }
- }
- // adjust the layout dimensions
- this.layout_ht = max;
- this.layout_wd = current_pos_x;
- }
- else { // other default/top alignment
- max = client_area.Width;
- foreach (ListViewItem item in items) {
- item.location.X = current_pos_x +
- horizontal_spacing;
-
- item.location.Y = current_pos_y;
- item.CalcListViewItem ();
- current_pos_x += item_wd;
-
- current ++; // just to know about the last element
- // we just did the last item
- if (current == items.Count) {
- if (max < current_pos_x)
- max = current_pos_x;
- current_pos_y = item.EntireRect.Bottom;
- break;
- }
- else {
- // is there enough space for another column?
- if ((current_pos_x + horizontal_spacing
- + item_wd) <= client_area.Width)
- continue;
- else {
- // start another row
- // make current_pos_x as the
- // max value and reset
- // current_pos_x value.
- max = current_pos_x;
- current_pos_y += (item_ht +
- vertical_spacing);
- current_pos_x = 0;
- }
- }
- }
- // adjust the layout dimensions
- this.layout_wd = max;
- this.layout_ht = current_pos_y;
- }
- }
+ LayoutIcons (true, alignment == ListViewAlignment.Left,
+ ThemeEngine.Current.ListViewHorizontalSpacing,
+ ThemeEngine.Current.ListViewVerticalSpacing);
break;
case View.List:
- if (items.Count > 0) {
- items [0].CalcListViewItem ();
- item_ht = items [0].EntireRect.Height;
- item_wd = items [0].EntireRect.Width;
-
- max = client_area.Height / item_ht;
- if (max == 0)
- max = 1; // we draw at least one row
-
- foreach (ListViewItem item in items) {
- item.location.X = current_pos_x;
- item.location.Y = current_pos_y;
- item.CalcListViewItem ();
- current ++;
- if (current == max) {
- current_pos_x += item_wd;
- current_pos_y = 0;
- current = 0;
- }
- else
- current_pos_y += item_ht;
- }
-
- // adjust the layout dimensions
- this.layout_ht = max * item_ht;
- if (current == 0) // we have fully filled layout
- this.layout_wd = current_pos_x;
- else
- this.layout_wd = current_pos_x + item_wd;
- }
+ LayoutIcons (false, true, 4, 2);
break;
}
CalculateScrollBars ();
-
}
-
- // Event Handlers
- private void ListView_DoubleClick (object sender, EventArgs e)
+
+ internal void UpdateSelection (ListViewItem item)
+ {
+ if (item.Selected) {
+
+ if (!CanMultiselect && SelectedItems.Count > 0) {
+ SelectedItems.Clear ();
+ }
+
+ if (!SelectedItems.list.Contains (item)) {
+ SelectedItems.list.Add (item);
+ }
+ } else {
+ SelectedItems.list.Remove (item);
+ }
+ }
+
+ private bool KeySearchString (KeyEventArgs ke)
+ {
+ int current_tickcnt = Environment.TickCount;
+ if (keysearch_tickcnt > 0 && current_tickcnt - keysearch_tickcnt > keysearch_keydelay) {
+ keysearch_text = string.Empty;
+ }
+
+ keysearch_text += (char) ke.KeyData;
+ 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 (Items [i]);
+ items [i].Selected = true;
+ EnsureVisible (i);
+ break;
+ }
+ i = (i + 1 < Items.Count) ? i+1 : 0;
+
+ if (i == start)
+ break;
+ }
+ return true;
+ }
+
+ int GetAdjustedIndex (Keys key)
+ {
+ int result = -1;
+
+ if (View == View.Details) {
+ if (key == Keys.Up)
+ result = FocusedItem.Index - 1;
+ else if (key == Keys.Down) {
+ result = FocusedItem.Index + 1;
+ if (result == items.Count)
+ result = -1;
+ }
+ return result;
+ }
+
+ int row = FocusedItem.row;
+ int col = FocusedItem.col;
+
+ switch (key) {
+ case Keys.Left:
+ if (col == 0)
+ return -1;
+ return item_matrix [row, col - 1].Index;
+
+ case Keys.Right:
+ if (col == (cols - 1))
+ return -1;
+ while (item_matrix [row, col + 1] == null)
+ row--;
+ return item_matrix [row, col + 1].Index;
+
+ case Keys.Up:
+ if (row == 0)
+ return -1;
+ return item_matrix [row - 1, col].Index;
+
+ case Keys.Down:
+ if (row == (rows - 1) || row == Items.Count - 1)
+ return -1;
+ while (item_matrix [row + 1, col] == null)
+ col--;
+ return item_matrix [row + 1, col].Index;
+
+ default:
+ return -1;
+ }
+ }
+
+ ListViewItem selection_start;
+
+ private bool SelectItems (ArrayList sel_items)
{
- if (this.activation == ItemActivation.Standard
- && this.ItemActivate != null)
- this.ItemActivate (this, e);
+ bool changed = false;
+ multiselecting = true;
+ ArrayList curr_items = (ArrayList) SelectedItems.list.Clone ();
+ foreach (ListViewItem item in curr_items)
+ if (!sel_items.Contains (item)) {
+ item.Selected = false;
+ changed = true;
+ }
+ foreach (ListViewItem item in sel_items)
+ if (!item.Selected) {
+ item.Selected = true;
+ changed = true;
+ }
+ multiselecting = false;
+ return changed;
+ }
+
+ private void UpdateMultiSelection (int index)
+ {
+ bool shift_pressed = (XplatUI.State.ModifierKeys & Keys.Shift) != 0;
+ bool ctrl_pressed = (XplatUI.State.ModifierKeys & Keys.Control) != 0;
+ ListViewItem item = items [index];
+
+ if (shift_pressed && selection_start != null) {
+ ArrayList list = new ArrayList ();
+ int start = Math.Min (selection_start.Index, index);
+ int end = Math.Max (selection_start.Index, index);
+ if (View == View.Details) {
+ for (int i = start; i <= end; i++)
+ list.Add (items [i]);
+ } else {
+ int left = Math.Min (items [start].col, items [end].col);
+ int right = Math.Max (items [start].col, items [end].col);
+ int top = Math.Min (items [start].row, items [end].row);
+ int bottom = Math.Max (items [start].row, items [end].row);
+ foreach (ListViewItem curr in items)
+ if (curr.row >= top && curr.row <= bottom &&
+ curr.col >= left && curr.col <= right)
+ list.Add (curr);
+ }
+ if (SelectItems (list))
+ OnSelectedIndexChanged (EventArgs.Empty);
+ } else if (!ctrl_pressed) {
+ SelectedItems.Clear ();
+ item.Selected = true;
+ selection_start = item;
+ OnSelectedIndexChanged (EventArgs.Empty);
+ }
}
private void ListView_KeyDown (object sender, KeyEventArgs ke)
{
- int index = -1;
- if (ke.Handled || Items.Count == 0)
+ if (ke.Handled || Items.Count == 0 || !item_control.Visible)
return;
+ int index = -1;
ke.Handled = true;
- switch (ke.KeyCode) {
+ if (FocusedItem == null)
+ SetFocusedItem (Items [0]);
- case Keys.ControlKey:
- ctrl_pressed = true;
- break;
-
- case Keys.Down:
- if (focused_item != null && focused_item.Index + 1 < Items.Count) {
- index = focused_item.Index + 1;
- }
- break;
+ switch (ke.KeyCode) {
case Keys.End:
index = Items.Count - 1;
break;
case Keys.Left:
- index = -1;
- if (focused_item != null)
- index = focused_item.Index;
- else
- break;
-
- if (index > 0)
- index -= 1;
-
- break;
-
case Keys.Right:
- if (focused_item != null)
- index = focused_item.Index + 1;
- else
- index = 1;
-
- if (index == items.Count)
- index = -1;
-
- break;
-
- case Keys.ShiftKey:
- shift_pressed = true;
- break;
-
case Keys.Up:
- if (focused_item != null)
- index = focused_item.Index;
- else
- break;
-
- if (index > 0)
- index--;
-
- if (index < 0) {
- index = -1;
- }
+ case Keys.Down:
+ index = GetAdjustedIndex (ke.KeyCode);
break;
default:
- ke.Handled = false;
- break;
+ ke.Handled = KeySearchString (ke);
+ return;
}
- if (index != -1) {
+ if (index == -1)
+ return;
+
+ if (MultiSelect)
+ UpdateMultiSelection (index);
+ else if (!items [index].Selected) {
items [index].Selected = true;
- SetFocusedItem (items [index]);
- EnsureVisible (index);
+ OnSelectedIndexChanged (EventArgs.Empty);
}
+
+ SetFocusedItem (items [index]);
+ EnsureVisible (index);
}
- private void ListView_KeyUp (object sender, KeyEventArgs ke)
- {
- if (!ke.Handled) {
- if (ke.KeyCode == Keys.ControlKey)
- this.ctrl_pressed = false;
+
+ internal class ItemControl : Control {
+
+ ListView owner;
+ ListViewItem clicked_item;
+ ListViewItem last_clicked_item;
+ bool hover_processed = false;
+ bool checking = false;
- if (ke.KeyCode == Keys.ShiftKey)
- this.shift_pressed = false;
- ke.Handled = true;
+ public ItemControl (ListView owner)
+ {
+ this.owner = owner;
+ DoubleClick += new EventHandler(ItemsDoubleClick);
+ MouseDown += new MouseEventHandler(ItemsMouseDown);
+ MouseMove += new MouseEventHandler(ItemsMouseMove);
+ MouseHover += new EventHandler(ItemsMouseHover);
+ MouseUp += new MouseEventHandler(ItemsMouseUp);
}
- }
- private void ListView_MouseDown (object sender, MouseEventArgs me)
- {
- if (items.Count == 0)
- return;
+ void ItemsDoubleClick (object sender, EventArgs e)
+ {
+ if (owner.activation == ItemActivation.Standard && owner.ItemActivate != null)
+ owner.ItemActivate (this, e);
+ }
- Point hit = Point.Empty;
- if (this.HeaderStyle != ColumnHeaderStyle.None) {
- // take horizontal scrolling into account
- hit = new Point (me.X + h_marker, me.Y);
-
- // hit test on columns
- if (this.view == View.Details && this.columns.Count > 0) {
- foreach (ColumnHeader col in this.columns) {
- if (col.Rect.Contains (hit)) {
- this.clicked_column = col;
- this.Capture = true;
- break;
- }
- }
+ enum BoxSelect {
+ None,
+ Normal,
+ Shift,
+ Control
+ }
+
+ BoxSelect box_select_mode = BoxSelect.None;
+ ArrayList prev_selection;
+ Point box_select_start;
- if (this.clicked_column != null) {
- this.clicked_column.pressed = true;
- this.Redraw (false);
+ Rectangle box_select_rect;
+ internal Rectangle BoxSelectRectangle {
+ get { return box_select_rect; }
+ set {
+ if (box_select_rect == value)
return;
+
+ InvalidateBoxSelectRect ();
+ box_select_rect = value;
+ InvalidateBoxSelectRect ();
+ }
+ }
+
+ void InvalidateBoxSelectRect ()
+ {
+ if (BoxSelectRectangle.Size.IsEmpty)
+ return;
+
+ Rectangle edge = BoxSelectRectangle;
+ edge.X -= 1;
+ edge.Y -= 1;
+ edge.Width += 2;
+ edge.Height = 2;
+ Invalidate (edge);
+ edge.Y = BoxSelectRectangle.Bottom - 1;
+ Invalidate (edge);
+ edge.Y = BoxSelectRectangle.Y - 1;
+ edge.Width = 2;
+ edge.Height = BoxSelectRectangle.Height + 2;
+ Invalidate (edge);
+ edge.X = BoxSelectRectangle.Right - 1;
+ Invalidate (edge);
+ }
+
+ private Rectangle CalculateBoxSelectRectangle (Point pt)
+ {
+ int left = Math.Min (box_select_start.X, pt.X);
+ int right = Math.Max (box_select_start.X, pt.X);
+ int top = Math.Min (box_select_start.Y, pt.Y);
+ int bottom = Math.Max (box_select_start.Y, pt.Y);
+ return Rectangle.FromLTRB (left, top, right, bottom);
+ }
+
+ ArrayList BoxSelectedItems {
+ get {
+ ArrayList result = new ArrayList ();
+ foreach (ListViewItem item in owner.Items) {
+ Rectangle r = item.Bounds;
+ r.X += r.Width / 4;
+ r.Y += r.Height / 4;
+ r.Width /= 2;
+ r.Height /= 2;
+ if (BoxSelectRectangle.IntersectsWith (r))
+ result.Add (item);
}
+ return result;
}
}
- // hit test on items
- // we need to take scrolling into account
- hit = new Point (me.X + h_marker, me.Y + v_marker);
- foreach (ListViewItem item in this.items) {
- if (item.CheckRect.Contains (hit)) {
- CheckState curr_state = item.Checked ?
- CheckState.Checked : CheckState.Unchecked;
- if (item.Checked)
- item.Checked = false;
- else
- item.Checked = true;
+ private bool PerformBoxSelection (Point pt)
+ {
+ if (box_select_mode == BoxSelect.None)
+ return false;
- CheckState new_state = item.Checked ?
- CheckState.Checked : CheckState.Unchecked;
- this.Redraw (false);
+ BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
+
+ ArrayList box_items = BoxSelectedItems;
+
+ ArrayList items;
- // Raise the ItemCheck event
- ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index,
- curr_state,
- new_state);
- this.OnItemCheck (ice);
+ switch (box_select_mode) {
+
+ case BoxSelect.Normal:
+ items = box_items;
+ break;
+
+ case BoxSelect.Control:
+ items = new ArrayList ();
+ foreach (ListViewItem item in prev_selection)
+ if (!box_items.Contains (item))
+ items.Add (item);
+ foreach (ListViewItem item in box_items)
+ if (!prev_selection.Contains (item))
+ items.Add (item);
+ break;
+
+ case BoxSelect.Shift:
+ items = box_items;
+ foreach (ListViewItem item in box_items)
+ prev_selection.Remove (item);
+ foreach (ListViewItem item in prev_selection)
+ items.Add (item);
break;
+
+ default:
+ throw new Exception ("Unexpected Selection mode: " + box_select_mode);
}
- if (this.view == View.Details &&
- this.FullRowSelect == false) {
- if (item.LabelRect.Contains (hit)) {
- this.clicked_item = item;
- break;
+ SuspendLayout ();
+ owner.SelectItems (items);
+ ResumeLayout ();
+
+ return true;
+ }
+
+ private void ToggleCheckState (ListViewItem item)
+ {
+ CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
+ item.Checked = !item.Checked;
+ CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
+
+ ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
+ owner.OnItemCheck (ice);
+ }
+
+ private void ItemsMouseDown (object sender, MouseEventArgs me)
+ {
+ if (owner.items.Count == 0)
+ return;
+
+ Point pt = new Point (me.X, me.Y);
+ foreach (ListViewItem item in owner.items) {
+ if (me.Clicks == 1 && item.CheckRectReal.Contains (pt)) {
+ checking = true;
+ if (me.Clicks > 1)
+ return;
+ ToggleCheckState (item);
+ return;
+ }
+
+ if (owner.View == View.Details && !owner.FullRowSelect) {
+ if (item.GetBounds (ItemBoundsPortion.Label).Contains (pt)) {
+ clicked_item = item;
+ break;
+ }
+ } else {
+ if (item.Bounds.Contains (pt)) {
+ clicked_item = item;
+ break;
+ }
}
}
- else {
- if (item.EntireRect.Contains (hit)) {
- this.clicked_item = item;
- break;
+
+
+ if (clicked_item != null) {
+ owner.SetFocusedItem (clicked_item);
+ bool changed = !clicked_item.Selected;
+ if (owner.MultiSelect && (XplatUI.State.ModifierKeys & Keys.Control) == 0)
+ owner.UpdateMultiSelection (clicked_item.Index);
+ else
+ clicked_item.Selected = true;
+
+ if (changed)
+ owner.OnSelectedIndexChanged (EventArgs.Empty);
+
+ // Raise double click if the item was clicked. On MS the
+ // double click is only raised if you double click an item
+ if (me.Clicks > 1) {
+ owner.OnDoubleClick (EventArgs.Empty);
+ if (owner.CheckBoxes)
+ ToggleCheckState (clicked_item);
+ } else if (me.Clicks == 1)
+ owner.OnClick (EventArgs.Empty);
+ } else {
+ if (owner.MultiSelect) {
+ Keys mods = XplatUI.State.ModifierKeys;
+ if ((mods & Keys.Shift) != 0)
+ box_select_mode = BoxSelect.Shift;
+ else if ((mods & Keys.Control) != 0)
+ box_select_mode = BoxSelect.Control;
+ else
+ box_select_mode = BoxSelect.Normal;
+ box_select_start = pt;
+ prev_selection = (ArrayList) owner.SelectedItems.list.Clone ();
+ } else if (owner.selected_indices.Count > 0) {
+ owner.SelectedItems.Clear ();
+ owner.OnSelectedIndexChanged (EventArgs.Empty);
}
}
}
- // set the FocusedItem to be the current clicked_item
- SetFocusedItem (clicked_item);
+ private void ItemsMouseMove (object sender, MouseEventArgs me)
+ {
+ if (PerformBoxSelection (new Point (me.X, me.Y)))
+ return;
- if (clicked_item != null) {
- bool changed = !clicked_item.Selected;
- clicked_item.Selected = true;
-
- // Only Raise the event if the selected item has changed
- if (changed)
- OnSelectedIndexChanged (EventArgs.Empty);
+ if (owner.HoverSelection && hover_processed) {
- // Raise double click if the item was clicked. On MS the
- // double click is only raised if you double click an item
- if (me.Clicks > 1 && this.clicked_item != null)
- OnDoubleClick (EventArgs.Empty);
+ Point pt = PointToClient (Control.MousePosition);
+ ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
+ if (item == null || item.Selected)
+ return;
- this.Redraw (false);
- } else if (selected_indices.Count > 0) {
- // NOTE: selected_indices isn't computed properly so
- // this doesn't actually work
-
- // Raise the event if there was at least one item
- // selected and the user click on a dead area (unselecting all)
- OnSelectedIndexChanged (EventArgs.Empty);
- Redraw (false);
+ hover_processed = false;
+ XplatUI.ResetMouseHover (Handle);
+ }
}
- }
- private void ListView_MouseHover (object sender, EventArgs e)
- {
- // handle the hover events only when the mouse
- // is not captured.
- if (this.hover_selection == false || this.Capture)
- return;
- // hit test for the items
- Point hit = this.PointToClient (Control.MousePosition);
- ListViewItem item = this.GetItemAt (hit.X, hit.Y);
+ private void ItemsMouseHover (object sender, EventArgs e)
+ {
+ if (Capture || !owner.HoverSelection)
+ return;
- if (item != null) {
- item.Selected = true;
- // Raise the event
- this.OnSelectedIndexChanged (new EventArgs ());
+ hover_processed = true;
+ Point pt = PointToClient (Control.MousePosition);
+ ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
- this.Redraw (false);
- }
- }
+ if (item == null)
+ return;
- private void ListView_MouseMove (object sender, MouseEventArgs me)
- {
- // Column header is always at the top. It can
- // scroll only horizontally. So, we have to take
- // only horizontal scrolling into account
- Point hit = new Point (me.X + h_marker, me.Y);
-
- // non-null clicked_col means mouse down has happened
- // on a column
- if (this.clicked_column != null) {
- if (this.clicked_column.pressed == false &&
- this.clicked_column.Rect.Contains (hit)) {
- this.clicked_column.pressed = true;
- this.Redraw (false);
- }
- else if (this.clicked_column.pressed &&
- ! this.clicked_column.Rect.Contains (hit)) {
- this.clicked_column.pressed = false;
- this.Redraw (false);
- }
+ item.Selected = true;
+ owner.OnSelectedIndexChanged (new EventArgs ());
}
- }
- private void ListView_MouseUp (object sender, MouseEventArgs me)
- {
- this.Capture = false;
- if (items.Count == 0)
- return;
+ private void ItemsMouseUp (object sender, MouseEventArgs me)
+ {
+ Capture = false;
+ if (owner.Items.Count == 0)
+ return;
- Point hit = new Point (me.X, me.Y);
+ Point pt = new Point (me.X, me.Y);
- if (this.clicked_column != null) {
- if (this.clicked_column.pressed) {
- this.clicked_column.pressed = false;
- this.Redraw (false);
+ Rectangle rect = Rectangle.Empty;
+ if (clicked_item != null) {
+ if (owner.view == View.Details && !owner.full_row_select)
+ rect = clicked_item.GetBounds (ItemBoundsPortion.Label);
+ else
+ rect = clicked_item.Bounds;
- // Raise the ColumnClick event
- this.OnColumnClick (new ColumnClickEventArgs
- (this.clicked_column.Index));
- }
- }
+ if (rect.Contains (pt)) {
+ switch (owner.activation) {
+ case ItemActivation.OneClick:
+ owner.OnItemActivate (EventArgs.Empty);
+ break;
- // Raise the ItemActivate event
- Rectangle rect = Rectangle.Empty;
- if (this.clicked_item != null) {
- if (this.view == View.Details && !this.full_row_select)
- rect = this.clicked_item.LabelRect;
- else
- rect = this.clicked_item.EntireRect;
-
- // We handle double click in a separate handler
- if (this.activation != ItemActivation.Standard &&
- rect.Contains (hit)) {
- if (this.activation == ItemActivation.OneClick)
- this.ItemActivate (this, EventArgs.Empty);
-
- // ItemActivate is raised on the second click on the same item
- else if (this.activation == ItemActivation.TwoClick) {
- if (this.last_clicked_item == this.clicked_item) {
- this.ItemActivate (this, EventArgs.Empty);
- this.last_clicked_item = null;
+ case ItemActivation.TwoClick:
+ if (last_clicked_item == clicked_item) {
+ owner.OnItemActivate (EventArgs.Empty);
+ last_clicked_item = null;
+ } else
+ last_clicked_item = clicked_item;
+ break;
+ default:
+ // DoubleClick activation is handled in another handler
+ break;
}
- else
- this.last_clicked_item = this.clicked_item;
}
+ } else if (!checking && owner.SelectedItems.Count > 0 && BoxSelectRectangle.Size.IsEmpty) {
+ // Need this to clean up background clicks
+ owner.SelectedItems.Clear ();
+ owner.OnSelectedIndexChanged (EventArgs.Empty);
}
+
+ clicked_item = null;
+ box_select_start = Point.Empty;
+ BoxSelectRectangle = Rectangle.Empty;
+ prev_selection = null;
+ box_select_mode = BoxSelect.None;
+ checking = false;
+ }
+
+ internal override void OnPaintInternal (PaintEventArgs pe)
+ {
+ ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
}
- this.clicked_column = null;
- this.clicked_item = null;
+ internal override void OnGotFocusInternal (EventArgs e)
+ {
+ owner.Focus ();
+ }
}
- private void ListView_Paint (object sender, PaintEventArgs pe)
+ internal override void OnPaintInternal (PaintEventArgs pe)
{
- if (this.Width <= 0 || this.Height <= 0 ||
- this.Visible == false || this.updating == true)
+ if (updating)
return;
CalculateScrollBars ();
+ }
+
+ void FocusChanged (object o, EventArgs args)
+ {
+ if (Items.Count == 0)
+ return;
- ThemeEngine.Current.DrawListView (pe.Graphics,
- pe.ClipRectangle, this);
-
- // Raise the Paint event
- if (Paint != null)
- Paint (this, pe);
+ if (FocusedItem == null)
+ SetFocusedItem (Items [0]);
+
+ item_control.Invalidate (FocusedItem.Bounds);
+ }
+
+ private void ListView_MouseWheel (object sender, MouseEventArgs me)
+ {
+ if (Items.Count == 0)
+ return;
+
+ int lines = me.Delta / 120;
+
+ if (lines == 0)
+ return;
+
+ switch (View) {
+ case View.Details:
+ case View.SmallIcon:
+ Scroll (v_scroll, -Items [0].Bounds.Height * SystemInformation.MouseWheelScrollLines * lines);
+ break;
+ case View.LargeIcon:
+ Scroll (v_scroll, -(Items [0].Bounds.Height + ThemeEngine.Current.ListViewVerticalSpacing) * lines);
+ break;
+ case View.List:
+ Scroll (h_scroll, -Items [0].Bounds.Width * lines);
+ break;
+ }
}
private void ListView_SizeChanged (object sender, EventArgs e)
if (h_marker != h_scroll.Value) {
int pixels = h_marker - h_scroll.Value;
- Rectangle area = client_area;
-
- if (View == View.Details && Columns.Count > 0) {
- area.Y += Columns[0].Ht;
- area.Height -= Columns[0].Ht;
- }
h_marker = h_scroll.Value;
- XplatUI.ScrollWindow (Handle, area, pixels, 0, false);
+ if (header_control.Visible)
+ XplatUI.ScrollWindow (header_control.Handle, pixels, 0, false);
+
+ XplatUI.ScrollWindow (item_control.Handle, pixels, 0, false);
}
}
// kept pressed at the end
if (v_marker != v_scroll.Value) {
int pixels = v_marker - v_scroll.Value;
- Rectangle area = client_area;
-
- if (View == View.Details && Columns.Count > 0) {
- area.Y += Columns[0].Ht;
- area.Height -= Columns[0].Ht;
- }
-
+ Rectangle area = item_control.ClientRectangle;
v_marker = v_scroll.Value;
- XplatUI.ScrollWindow (Handle, area, 0, pixels, false);
+ XplatUI.ScrollWindow (item_control.Handle, area, 0, pixels, false);
}
}
#endregion // Internal Methods Properties
h_scroll.Dispose ();
v_scroll.Dispose ();
- if (large_image_list != null)
- large_image_list.Dispose ();
-
- if (small_image_list != null)
- small_image_list.Dispose ();
-
- if (state_image_list != null)
- state_image_list.Dispose ();
+ large_image_list = null;
+ small_image_list = null;
+ state_image_list = null;
}
base.Dispose (disposing);
protected override void OnHandleCreated (EventArgs e)
{
base.OnHandleCreated (e);
- SuspendLayout ();
- Controls.AddImplicit (this.v_scroll);
- Controls.AddImplicit (this.h_scroll);
- ResumeLayout ();
+ Sort ();
}
protected override void OnHandleDestroyed (EventArgs e)
public void Clear ()
{
- SetFocusedItem (null);
columns.Clear ();
items.Clear (); // Redraw (true) called here
}
public void EnsureVisible (int index)
{
- if (index < 0 || index >= this.items.Count || this.scrollable == false)
+ if (index < 0 || index >= items.Count || scrollable == false)
return;
- // dimensions of visible area
- int view_wd = client_area.Width;
- int view_ht = client_area.Height;
- // visible area is decided by the h_marker and v_marker
- Rectangle view_rect = new Rectangle (h_marker, v_marker, view_wd, view_ht);
-
- // an item's bounding rect
- Rectangle rect = this.items [index].EntireRect;
+ Rectangle view_rect = item_control.ClientRectangle;
+ Rectangle bounds = items [index].Bounds;
- // we don't need to do anything if item is visible.
- // visible area is represented by (0,0,view_wd,view_ht)
- if (view_rect.Contains (rect))
+ if (view_rect.Contains (bounds))
return;
- // Scroll Left or Up
- if ((rect.Left < view_rect.Left) || (rect.Top < view_rect.Top)) {
- if (rect.Left < view_rect.Left)
- this.h_scroll.Value -= (view_rect.Left - rect.Left);
- if (rect.Top < view_rect.Top)
- this.v_scroll.Value -= (view_rect.Top - rect.Top);
- }
- // Scroll Right or Down
- else {
- if (rect.Right > view_rect.Right)
- this.h_scroll.Value += (rect.Right - view_rect.Right);
- if (rect.Bottom > view_rect.Bottom)
- this.v_scroll.Value += (rect.Bottom - view_rect.Bottom);
- }
+ if (bounds.Left < 0)
+ h_scroll.Value += bounds.Left;
+ else if (bounds.Right > view_rect.Right)
+ h_scroll.Value += (bounds.Right - view_rect.Right);
+
+ if (bounds.Top < 0)
+ v_scroll.Value += bounds.Top;
+ else if (bounds.Bottom > view_rect.Bottom)
+ v_scroll.Value += (bounds.Bottom - view_rect.Bottom);
}
public ListViewItem GetItemAt (int x, int y)
public Rectangle GetItemRect (int index, ItemBoundsPortion portion)
{
if (index < 0 || index >= items.Count)
- throw new IndexOutOfRangeException ("Invalid Index");
+ throw new IndexOutOfRangeException ("index");
return items [index].GetBounds (portion);
}
public void Sort ()
{
- if (sort_order != SortOrder.None)
- items.list.Sort (item_sorter);
-
- if (sort_order == SortOrder.Descending)
- items.list.Reverse ();
-
- this.Redraw (true);
+ Sort (true);
+ }
+
+ // we need this overload to reuse the logic for sorting, while allowing
+ // redrawing to be done by caller or have it done by this method when
+ // sorting is really performed
+ //
+ // ListViewItemCollection's Add and AddRange methods call this overload
+ // with redraw set to false, as they take care of redrawing themselves
+ // (they even want to redraw the listview if no sort is performed, as
+ // an item was added), while ListView.Sort () only wants to redraw if
+ // sorting was actually performed
+ private void Sort (bool redraw)
+ {
+ if (!IsHandleCreated || item_sorter == null) {
+ return;
+ }
+
+ items.list.Sort (item_sorter);
+ if (redraw)
+ this.Redraw (true);
}
public override string ToString ()
#region Subclasses
+
+ class HeaderControl : Control {
+
+ ListView owner;
+ bool column_resize_active = false;
+ ColumnHeader resize_column;
+ ColumnHeader clicked_column;
+ ColumnHeader drag_column;
+ int drag_x;
+ int drag_to_index = -1;
+
+ public HeaderControl (ListView owner)
+ {
+ this.owner = owner;
+ MouseDown += new MouseEventHandler (HeaderMouseDown);
+ MouseMove += new MouseEventHandler (HeaderMouseMove);
+ MouseUp += new MouseEventHandler (HeaderMouseUp);
+ }
+
+ private ColumnHeader ColumnAtX (int x)
+ {
+ Point pt = new Point (x, 0);
+ ColumnHeader result = null;
+ foreach (ColumnHeader col in owner.Columns) {
+ if (col.Rect.Contains (pt)) {
+ result = col;
+ break;
+ }
+ }
+ return result;
+ }
+
+ private int GetReorderedIndex (ColumnHeader col)
+ {
+ if (owner.reordered_column_indices == null)
+ return col.Index;
+ else
+ for (int i = 0; i < owner.Columns.Count; i++)
+ if (owner.reordered_column_indices [i] == col.Index)
+ return i;
+ throw new Exception ("Column index missing from reordered array");
+ }
+
+ private void HeaderMouseDown (object sender, MouseEventArgs me)
+ {
+ if (resize_column != null) {
+ column_resize_active = true;
+ Capture = true;
+ return;
+ }
+
+ clicked_column = ColumnAtX (me.X + owner.h_marker);
+
+ if (clicked_column != null) {
+ Capture = true;
+ if (owner.AllowColumnReorder) {
+ drag_x = me.X;
+ drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
+ drag_column.column_rect = clicked_column.Rect;
+ drag_to_index = GetReorderedIndex (clicked_column);
+ }
+ clicked_column.pressed = true;
+ Rectangle bounds = clicked_column.Rect;
+ bounds.X -= owner.h_marker;
+ Invalidate (bounds);
+ return;
+ }
+ }
+
+ private void HeaderMouseMove (object sender, MouseEventArgs me)
+ {
+ Point pt = new Point (me.X + owner.h_marker, me.Y);
+
+ if (column_resize_active) {
+ resize_column.Width = pt.X - resize_column.X;
+ if (resize_column.Width < 0)
+ resize_column.Width = 0;
+ return;
+ }
+
+ resize_column = null;
+
+ if (clicked_column != null) {
+ if (owner.AllowColumnReorder) {
+ Rectangle r;
+
+ r = drag_column.column_rect;
+ r.X = clicked_column.Rect.X + me.X - drag_x;
+ drag_column.column_rect = r;
+
+ int x = me.X + owner.h_marker;
+ ColumnHeader over = ColumnAtX (x);
+ if (over == null)
+ drag_to_index = owner.Columns.Count;
+ else if (x < over.X + over.Width / 2)
+ drag_to_index = GetReorderedIndex (over);
+ else
+ drag_to_index = GetReorderedIndex (over) + 1;
+ Invalidate ();
+ } else {
+ 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);
+ }
+ }
+ return;
+ }
+
+ for (int i = 0; i < owner.Columns.Count; i++) {
+ Rectangle zone = owner.Columns [i].Rect;
+ zone.X = zone.Right - 5;
+ zone.Width = 10;
+ if (zone.Contains (pt)) {
+ if (i < owner.Columns.Count - 1 && owner.Columns [i + 1].Width == 0)
+ i++;
+ resize_column = owner.Columns [i];
+ break;
+ }
+ }
+
+ if (resize_column == null)
+ Cursor = Cursors.Default;
+ else
+ Cursor = Cursors.VSplit;
+ }
+
+ void HeaderMouseUp (object sender, MouseEventArgs me)
+ {
+ Capture = false;
+
+ if (column_resize_active) {
+ column_resize_active = false;
+ resize_column = null;
+ Cursor = Cursors.Default;
+ return;
+ }
+
+ if (clicked_column != null && clicked_column.pressed) {
+ clicked_column.pressed = false;
+ Rectangle bounds = clicked_column.Rect;
+ bounds.X -= owner.h_marker;
+ Invalidate (bounds);
+ owner.OnColumnClick (new ColumnClickEventArgs (clicked_column.Index));
+ }
+
+ if (drag_column != null && owner.AllowColumnReorder) {
+ drag_column = null;
+ if (drag_to_index > GetReorderedIndex (clicked_column))
+ drag_to_index--;
+ if (owner.GetReorderedColumn (drag_to_index) != clicked_column)
+ owner.ReorderColumn (clicked_column, drag_to_index);
+ drag_to_index = -1;
+ Invalidate ();
+ }
+
+ clicked_column = null;
+ }
+
+ internal override void OnPaintInternal (PaintEventArgs pe)
+ {
+ if (owner.updating)
+ return;
+
+ Theme theme = ThemeEngine.Current;
+ theme.DrawListViewHeader (pe.Graphics, pe.ClipRectangle, this.owner);
+
+ if (drag_column == null)
+ return;
+
+ int target_x;
+ if (drag_to_index == owner.Columns.Count)
+ target_x = owner.GetReorderedColumn (drag_to_index - 1).Rect.Right - owner.h_marker;
+ else
+ target_x = owner.GetReorderedColumn (drag_to_index).Rect.X - owner.h_marker;
+ theme.DrawListViewHeaderDragDetails (pe.Graphics, owner, drag_column, target_x);
+ }
+
+ protected override void WndProc (ref Message m)
+ {
+ switch ((Msg)m.Msg) {
+ case Msg.WM_SETFOCUS:
+ owner.Focus ();
+ break;
+ default:
+ base.WndProc (ref m);
+ break;
+ }
+ }
+ }
+
+ private class ItemComparer : IComparer {
+ readonly SortOrder sort_order;
+
+ public ItemComparer (SortOrder sortOrder)
+ {
+ sort_order = sortOrder;
+ }
+
+ public int Compare (object x, object y)
+ {
+ ListViewItem item_x = x as ListViewItem;
+ ListViewItem item_y = y as ListViewItem;
+ if (sort_order == SortOrder.Ascending)
+ return String.Compare (item_x.Text, item_y.Text);
+ else
+ return String.Compare (item_y.Text, item_x.Text);
+ }
+ }
+
public class CheckedIndexCollection : IList, ICollection, IEnumerable
{
- internal ArrayList list;
- private ListView owner;
+ private readonly ListView owner;
#region Public Constructor
public CheckedIndexCollection (ListView owner)
{
- list = new ArrayList ();
this.owner = owner;
}
#endregion // Public Constructor
#region Public Properties
[Browsable (false)]
- public virtual int Count {
- get { return list.Count; }
+ public int Count {
+ get { return owner.CheckedItems.Count; }
}
- public virtual bool IsReadOnly {
+ public bool IsReadOnly {
get { return true; }
}
public int this [int index] {
get {
- if (index < 0 || index >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
- return (int) list [index];
+ int [] indices = GetIndices ();
+ if (index < 0 || index >= indices.Length)
+ throw new ArgumentOutOfRangeException ("index");
+ return indices [index];
}
}
#region Public Methods
public bool Contains (int checkedIndex)
{
- return list.Contains (checkedIndex);
+ int [] indices = GetIndices ();
+ for (int i = 0; i < indices.Length; i++) {
+ if (indices [i] == checkedIndex)
+ return true;
+ }
+ return false;
}
- public virtual IEnumerator GetEnumerator ()
+ public IEnumerator GetEnumerator ()
{
- return list.GetEnumerator ();
+ int [] indices = GetIndices ();
+ return indices.GetEnumerator ();
}
void ICollection.CopyTo (Array dest, int index)
{
- list.CopyTo (dest, index);
+ int [] indices = GetIndices ();
+ Array.Copy (indices, 0, dest, index, indices.Length);
}
int IList.Add (object value)
bool IList.Contains (object checkedIndex)
{
- return list.Contains (checkedIndex);
+ if (!(checkedIndex is int))
+ return false;
+ return Contains ((int) checkedIndex);
}
int IList.IndexOf (object checkedIndex)
{
- return list.IndexOf (checkedIndex);
+ if (!(checkedIndex is int))
+ return -1;
+ return IndexOf ((int) checkedIndex);
}
void IList.Insert (int index, object value)
public int IndexOf (int checkedIndex)
{
- return list.IndexOf (checkedIndex);
+ int [] indices = GetIndices ();
+ for (int i = 0; i < indices.Length; i++) {
+ if (indices [i] == checkedIndex)
+ return i;
+ }
+ return -1;
}
#endregion // Public Methods
+ private int [] GetIndices ()
+ {
+ int [] indices = new int [Count];
+ for (int i = 0; i < owner.CheckedItems.Count; i++) {
+ ListViewItem item = owner.CheckedItems [i];
+ indices [i] = item.Index;
+ }
+ return indices;
+ }
} // CheckedIndexCollection
public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
{
- internal ArrayList list;
- private ListView owner;
+ internal readonly ArrayList list;
+ private readonly ListView owner;
#region Public Constructor
public CheckedListViewItemCollection (ListView owner)
#region Public Properties
[Browsable (false)]
- public virtual int Count {
- get { return list.Count; }
+ public int Count {
+ get {
+ if (!owner.CheckBoxes)
+ return 0;
+ return list.Count;
+ }
}
- public virtual bool IsReadOnly {
+ public bool IsReadOnly {
get { return true; }
}
public ListViewItem this [int index] {
get {
- if (index < 0 || index >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException ("index");
return (ListViewItem) list [index];
}
}
#region Public Methods
public bool Contains (ListViewItem item)
{
+ if (!owner.CheckBoxes)
+ return false;
return list.Contains (item);
}
- public virtual void CopyTo (Array dest, int index)
+ public void CopyTo (Array dest, int index)
{
+ if (!owner.CheckBoxes)
+ return;
list.CopyTo (dest, index);
}
- public virtual IEnumerator GetEnumerator ()
+ public IEnumerator GetEnumerator ()
{
+ if (!owner.CheckBoxes)
+ return (new ListViewItem [0]).GetEnumerator ();
return list.GetEnumerator ();
}
bool IList.Contains (object item)
{
- return list.Contains (item);
+ if (!(item is ListViewItem))
+ return false;
+ return Contains ((ListViewItem) item);
}
int IList.IndexOf (object item)
{
- return list.IndexOf (item);
+ if (!(item is ListViewItem))
+ return -1;
+ return IndexOf ((ListViewItem) item);
}
void IList.Insert (int index, object value)
public int IndexOf (ListViewItem item)
{
+ if (!owner.CheckBoxes)
+ return -1;
return list.IndexOf (item);
}
#endregion // Public Methods
-
} // CheckedListViewItemCollection
public class ColumnHeaderCollection : IList, ICollection, IEnumerable
#region Public Properties
[Browsable (false)]
- public virtual int Count {
+ public int Count {
get { return list.Count; }
}
- public virtual bool IsReadOnly {
+ public bool IsReadOnly {
get { return false; }
}
public virtual ColumnHeader this [int index] {
get {
if (index < 0 || index >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
+ throw new ArgumentOutOfRangeException ("index");
return (ColumnHeader) list [index];
}
}
int idx;
value.owner = this.owner;
idx = list.Add (value);
- owner.Redraw (true);
+ if (owner.IsHandleCreated) {
+ owner.Redraw (true);
+ }
return idx;
}
return list.Contains (value);
}
- public virtual IEnumerator GetEnumerator ()
+ public IEnumerator GetEnumerator ()
{
return list.GetEnumerator ();
}
// LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
// but it's really only greater.
if (index < 0 || index > list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
+ throw new ArgumentOutOfRangeException ("index");
value.owner = this.owner;
list.Insert (index, value);
public virtual void RemoveAt (int index)
{
if (index < 0 || index >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
+ throw new ArgumentOutOfRangeException ("index");
// TODO: Update Column internal index ?
list.RemoveAt (index);
public class ListViewItemCollection : IList, ICollection, IEnumerable
{
internal ArrayList list;
- private ListView owner;
+ private readonly ListView owner;
#region Public Constructor
public ListViewItemCollection (ListView owner)
#region Public Properties
[Browsable (false)]
- public virtual int Count {
+ public int Count {
get { return list.Count; }
}
- public virtual bool IsReadOnly {
+ public bool IsReadOnly {
get { return false; }
}
public virtual ListViewItem this [int displayIndex] {
get {
if (displayIndex < 0 || displayIndex >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
+ throw new ArgumentOutOfRangeException ("displayIndex");
return (ListViewItem) list [displayIndex];
}
set {
if (displayIndex < 0 || displayIndex >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
+ throw new ArgumentOutOfRangeException ("displayIndex");
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");
- value.owner = this.owner;
+ value.Owner = owner;
list [displayIndex] = value;
owner.Redraw (true);
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");
- value.owner = this.owner;
+ value.Owner = owner;
list.Add (value);
- if (owner.Sorting != SortOrder.None)
- owner.Sort ();
-
+ owner.Sort (false);
owner.Redraw (true);
-
return value;
}
{
list.Clear ();
owner.SelectedItems.list.Clear ();
- owner.SelectedIndices.list.Clear ();
owner.CheckedItems.list.Clear ();
- owner.CheckedIndices.list.Clear ();
foreach (ListViewItem item in values) {
- item.owner = this.owner;
+ item.Owner = owner;
list.Add (item);
}
- if (owner.Sorting != SortOrder.None)
- owner.Sort ();
-
+ owner.Sort (false);
owner.Redraw (true);
}
public virtual void Clear ()
{
+ owner.SetFocusedItem (null);
+ owner.h_scroll.Value = owner.v_scroll.Value = 0;
list.Clear ();
owner.SelectedItems.list.Clear ();
- owner.SelectedIndices.list.Clear ();
owner.CheckedItems.list.Clear ();
- owner.CheckedIndices.list.Clear ();
owner.Redraw (true);
}
return list.Contains (item);
}
- public virtual void CopyTo (Array dest, int index)
+ public void CopyTo (Array dest, int index)
{
list.CopyTo (dest, index);
}
- public virtual IEnumerator GetEnumerator ()
+ public IEnumerator GetEnumerator ()
{
return list.GetEnumerator ();
}
else
li = new ListViewItem (item.ToString ());
- li.owner = this.owner;
+ li.Owner = owner;
result = list.Add (li);
owner.Redraw (true);
public ListViewItem Insert (int index, ListViewItem item)
{
- // LAMESPEC: MSDOCS say greater than or equal to the value of the Count property
- // but it's really only greater.
if (index < 0 || index > list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
+ throw new ArgumentOutOfRangeException ("index");
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");
- item.owner = this.owner;
+ item.Owner = owner;
list.Insert (index, item);
owner.Redraw (true);
return item;
return;
owner.SelectedItems.list.Remove (item);
- owner.SelectedIndices.list.Remove (item.Index);
owner.CheckedItems.list.Remove (item);
- owner.CheckedIndices.list.Remove (item.Index);
list.Remove (item);
owner.Redraw (true);
}
public virtual void RemoveAt (int index)
{
- if (index < 0 || index >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
-
+ ListViewItem item = this [index];
list.RemoveAt (index);
- owner.SelectedItems.list.RemoveAt (index);
- owner.SelectedIndices.list.RemoveAt (index);
- owner.CheckedItems.list.RemoveAt (index);
- owner.CheckedIndices.list.RemoveAt (index);
+ owner.SelectedItems.list.Remove (item);
+ owner.CheckedItems.list.Remove (item);
owner.Redraw (false);
}
#endregion // Public Methods
public class SelectedIndexCollection : IList, ICollection, IEnumerable
{
- internal ArrayList list;
- private ListView owner;
+ private readonly ListView owner;
#region Public Constructor
public SelectedIndexCollection (ListView owner)
{
- list = new ArrayList ();
this.owner = owner;
}
#endregion // Public Constructor
#region Public Properties
[Browsable (false)]
- public virtual int Count {
- get { return list.Count; }
+ public int Count {
+ get {
+ return owner.SelectedItems.Count;
+ }
}
- public virtual bool IsReadOnly {
+ public bool IsReadOnly {
get { return true; }
}
public int this [int index] {
get {
- if (index < 0 || index >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
- return (int) list [index];
+ int [] indices = GetIndices ();
+ if (index < 0 || index >= indices.Length)
+ throw new ArgumentOutOfRangeException ("index");
+ return indices [index];
}
}
bool ICollection.IsSynchronized {
- get { return list.IsSynchronized; }
+ get { return false; }
}
object ICollection.SyncRoot {
#region Public Methods
public bool Contains (int selectedIndex)
{
- return list.Contains (selectedIndex);
+ int [] indices = GetIndices ();
+ for (int i = 0; i < indices.Length; i++) {
+ if (indices [i] == selectedIndex)
+ return true;
+ }
+ return false;
}
- public virtual void CopyTo (Array dest, int index)
+ public void CopyTo (Array dest, int index)
{
- list.CopyTo (dest, index);
+ int [] indices = GetIndices ();
+ Array.Copy (indices, 0, dest, index, indices.Length);
}
- public virtual IEnumerator GetEnumerator ()
+ public IEnumerator GetEnumerator ()
{
- return list.GetEnumerator ();
+ int [] indices = GetIndices ();
+ return indices.GetEnumerator ();
}
int IList.Add (object value)
bool IList.Contains (object selectedIndex)
{
- return list.Contains (selectedIndex);
+ if (!(selectedIndex is int))
+ return false;
+ return Contains ((int) selectedIndex);
}
int IList.IndexOf (object selectedIndex)
{
- return list.IndexOf (selectedIndex);
+ if (!(selectedIndex is int))
+ return -1;
+ return IndexOf ((int) selectedIndex);
}
void IList.Insert (int index, object value)
public int IndexOf (int selectedIndex)
{
- return list.IndexOf (selectedIndex);
+ int [] indices = GetIndices ();
+ for (int i = 0; i < indices.Length; i++) {
+ if (indices [i] == selectedIndex)
+ return i;
+ }
+ return -1;
}
#endregion // Public Methods
+ private int [] GetIndices ()
+ {
+ int [] indices = new int [Count];
+ for (int i = 0; i < owner.SelectedItems.Count; i++) {
+ ListViewItem item = owner.SelectedItems [i];
+ indices [i] = item.Index;
+ }
+ return indices;
+ }
+
} // SelectedIndexCollection
public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
{
internal ArrayList list;
- private ListView owner;
+ private readonly ListView owner;
#region Public Constructor
public SelectedListViewItemCollection (ListView owner)
#region Public Properties
[Browsable (false)]
- public virtual int Count {
- get { return list.Count; }
+ public int Count {
+ get {
+ if (!owner.IsHandleCreated)
+ return 0;
+ return list.Count;
+ }
}
- public virtual bool IsReadOnly {
+ public bool IsReadOnly {
get { return true; }
}
public ListViewItem this [int index] {
get {
- if (index < 0 || index >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException ("index");
return (ListViewItem) list [index];
}
}
#endregion // Public Properties
#region Public Methods
- public virtual void Clear ()
+ public void Clear ()
{
- // mark the items as unselected before clearing the list
- for (int i = 0; i < list.Count; i++)
- ((ListViewItem) list [i]).selected = false;
+ if (!owner.IsHandleCreated)
+ return;
+
+ ArrayList copy = (ArrayList) list.Clone ();
+ for (int i = 0; i < copy.Count; i++)
+ ((ListViewItem) copy [i]).Selected = false;
list.Clear ();
-
- if (owner != null)
- owner.Invalidate ();
}
public bool Contains (ListViewItem item)
{
+ if (!owner.IsHandleCreated)
+ return false;
return list.Contains (item);
}
- public virtual void CopyTo (Array dest, int index)
+ public void CopyTo (Array dest, int index)
{
+ if (!owner.IsHandleCreated)
+ return;
list.CopyTo (dest, index);
}
- public virtual IEnumerator GetEnumerator ()
+ public IEnumerator GetEnumerator ()
{
+ if (!owner.IsHandleCreated)
+ return (new ListViewItem [0]).GetEnumerator ();
return list.GetEnumerator ();
}
bool IList.Contains (object item)
{
- return list.Contains (item);
+ if (!(item is ListViewItem))
+ return false;
+ return Contains ((ListViewItem) item);
}
int IList.IndexOf (object item)
{
- return list.IndexOf (item);
+ if (!(item is ListViewItem))
+ return -1;
+ return IndexOf ((ListViewItem) item);
}
void IList.Insert (int index, object value)
public int IndexOf (ListViewItem item)
{
+ if (!owner.IsHandleCreated)
+ return -1;
return list.IndexOf (item);
}
#endregion // Public Methods