//
// TODO:
// - Feedback for item activation, change in cursor types as mouse moves.
-// - HideSelection
// - LabelEdit
// - Drag and drop
private bool allow_column_reorder = false;
private bool auto_arrange = true;
private bool check_boxes = false;
- private CheckedIndexCollection checked_indices;
- private CheckedListViewItemCollection checked_items;
- private ColumnHeaderCollection columns;
+ private readonly CheckedIndexCollection checked_indices;
+ private readonly CheckedListViewItemCollection checked_items;
+ private readonly ColumnHeaderCollection columns;
internal ListViewItem focused_item;
private bool full_row_select = false;
private bool grid_lines = false;
private bool hide_selection = true;
private bool hover_selection = false;
private IComparer item_sorter;
- private ListViewItemCollection items;
+ private readonly ListViewItemCollection items;
private bool label_edit = false;
private bool label_wrap = true;
private bool multiselect = true;
private bool scrollable = true;
- private SelectedIndexCollection selected_indices;
- private SelectedListViewItemCollection selected_items;
+ private readonly SelectedIndexCollection selected_indices;
+ private readonly SelectedListViewItemCollection selected_items;
private SortOrder sort_order = SortOrder.None;
private ImageList state_image_list;
private bool updating = false;
public ListView ()
{
background_color = ThemeEngine.Current.ColorWindow;
+ items = new ListViewItemCollection (this);
checked_indices = new CheckedIndexCollection (this);
checked_items = new CheckedListViewItemCollection (this);
columns = new ColumnHeaderCollection (this);
foreground_color = SystemColors.WindowText;
- items = new ListViewItemCollection (this);
selected_indices = new SelectedIndexCollection (this);
selected_items = new SelectedListViewItemCollection (this);
header_control = new HeaderControl (this);
header_control.Visible = false;
+ Controls.AddImplicit (header_control);
+
item_control = new ItemControl (this);
- item_control.Visible = true;
+ Controls.AddImplicit (item_control);
+
+ h_scroll = new ImplicitHScrollBar ();
+ Controls.AddImplicit (this.h_scroll);
+
+ v_scroll = new ImplicitVScrollBar ();
+ Controls.AddImplicit (this.v_scroll);
- h_scroll = new HScrollBar ();
- v_scroll = new VScrollBar ();
h_marker = v_marker = 0;
keysearch_tickcnt = 0;
// event handlers
base.KeyDown += new KeyEventHandler(ListView_KeyDown);
- 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 {
- get {
- if (multiselect && (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0)
- return true;
- else
- return false;
- }
- }
-
#endregion // Private Internal Properties
#region Protected Properties
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);
}
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public ListViewItem FocusedItem {
get {
- if (focused_item == null && Focused && items.Count > 0)
- focused_item = items [0];
return focused_item;
}
}
[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 ();
}
}
}
}
}
+#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);
internal int LastVisibleIndex {
get {
- for (int i = FirstVisibleIndex; i < Items.Count; i++) {
- if (Items[i].Bounds.Y > 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;
}
}
+ internal void OnSelectedIndexChanged ()
+ {
+ if (IsHandleCreated)
+ OnSelectedIndexChanged (EventArgs.Empty);
+ }
+
internal int TotalWidth {
get { return Math.Max (this.Width, this.layout_wd); }
}
return ret_size;
}
+ const int max_wrap_padding = 38;
+
// Sets the size of the biggest item text as per the view
private void CalcTextSize ()
{
Size temp = Size.Empty;
if (this.check_boxes)
temp.Width += 2 * this.CheckBoxSize.Width;
- if (large_image_list != null)
- temp.Width += large_image_list.ImageSize.Width;
- if (temp.Width == 0)
- temp.Width = 43;
+ int icon_w = LargeImageList == null ? 12 : LargeImageList.ImageSize.Width;
+ temp.Width += icon_w + max_wrap_padding;
// wrapping is done for two lines only
if (text_size.Width > temp.Width) {
text_size.Width = temp.Width;
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 ()
{
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) {
item_control.Height = ClientRectangle.Height - header_control.Height;
- if (h_scroll.Visible) {
+ if (h_scroll.is_visible) {
h_scroll.Location = new Point (client_area.X, client_area.Bottom - h_scroll.Height);
h_scroll.Minimum = 0;
item_control.Height -= h_scroll.Height;
}
- if (header_control.Visible)
+ if (header_control.is_visible)
header_control.Width = ClientRectangle.Width;
item_control.Width = ClientRectangle.Width;
- if (v_scroll.Visible) {
+ if (v_scroll.is_visible) {
v_scroll.Location = new Point (client_area.Right - v_scroll.Width, client_area.Y);
v_scroll.Minimum = 0;
Size LargeIconItemSize {
get {
- int w = Math.Max (text_size.Width, 2 + CheckBoxSize.Width + LargeImageList.ImageSize.Width);
- int h = text_size.Height + 2 + Math.Max (CheckBoxSize.Height, LargeImageList.ImageSize.Height);
+ 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 w = text_size.Width + 2 + CheckBoxSize.Width + SmallImageList.ImageSize.Width;
- int h = Math.Max (text_size.Height, Math.Max (CheckBoxSize.Height, SmallImageList.ImageSize.Height));
+ 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);
}
}
{
header_control.Visible = false;
header_control.Size = Size.Empty;
+ item_control.Visible = true;
item_control.Location = Point.Empty;
if (items.Count == 0)
Rectangle area = ClientRectangle;
if (left_aligned) {
- rows = (int) Math.Floor ((double)area.Height / (double)(sz.Height + y_spacing));
- if (rows == 0)
+ 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 / (double)(sz.Width + x_spacing));
- if (cols == 0)
+ 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);
}
void LayoutHeader ()
{
- if (columns.Count == 0 || header_style == ColumnHeaderStyle.None) {
- header_control.Visible = false;
- header_control.Size = Size.Empty;
- return;
- }
-
int x = 0;
for (int i = 0; i < Columns.Count; i++) {
ColumnHeader col = GetReorderedColumn (i);
x += col.Wd;
}
- header_control.Width = x;
- header_control.Height = columns [0].Ht;
- header_control.Visible = true;
+ 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 ();
+ item_control.Visible = true;
item_control.Location = new Point (0, header_control.Height);
int y = 0;
CalculateScrollBars ();
}
- internal void UpdateSelection (ListViewItem item)
- {
- if (item.Selected) {
-
- if (!CanMultiselect && SelectedItems.Count > 0) {
- SelectedItems.Clear ();
- SelectedIndices.list.Clear ();
- }
-
- if (!SelectedItems.Contains (item)) {
- SelectedItems.list.Add (item);
- SelectedIndices.list.Add (item.Index);
- }
- } else {
- SelectedItems.list.Remove (item);
- SelectedIndices.list.Remove (item.Index);
+ bool HaveModKeys {
+ get {
+ return (XplatUI.State.ModifierKeys & (Keys.Control | Keys.Shift)) != 0;
}
}
return item_matrix [row - 1, col].Index;
case Keys.Down:
- if (row == (rows - 1))
+ if (row == (rows - 1) || row == Items.Count - 1)
return -1;
while (item_matrix [row + 1, col] == null)
col--;
ListViewItem selection_start;
- private void SelectItems (ArrayList sel_items)
+ private bool SelectItems (ArrayList sel_items)
{
- SelectedItems.Clear ();
- SelectedIndices.list.Clear ();
+ bool changed = false;
+ ArrayList curr_items = SelectedItems.List;
+ foreach (ListViewItem item in curr_items)
+ if (!sel_items.Contains (item)) {
+ item.Selected = false;
+ changed = true;
+ }
foreach (ListViewItem item in sel_items)
- item.Selected = true;
+ if (!item.Selected) {
+ item.Selected = true;
+ changed = true;
+ }
+ return changed;
}
private void UpdateMultiSelection (int index)
curr.col >= left && curr.col <= right)
list.Add (curr);
}
- SelectItems (list);
- } else if (!ctrl_pressed) {
+ if (SelectItems (list))
+ OnSelectedIndexChanged (EventArgs.Empty);
+ } else if (ctrl_pressed) {
+ item.Selected = !item.Selected;
+ selection_start = item;
+ OnSelectedIndexChanged (EventArgs.Empty);
+ } else {
SelectedItems.Clear ();
- SelectedIndices.list.Clear ();
item.Selected = true;
selection_start = item;
+ OnSelectedIndexChanged (EventArgs.Empty);
}
}
- private void ListView_KeyDown (object sender, KeyEventArgs ke)
- {
- if (ke.Handled || Items.Count == 0)
- return;
+ internal override bool InternalPreProcessMessage (ref Message msg)
+ {
+ if (msg.Msg == (int)Msg.WM_KEYDOWN) {
+ Keys key_data = (Keys)msg.WParam.ToInt32();
+ if (HandleNavKeys (key_data))
+ return true;
+ }
+ return base.InternalPreProcessMessage (ref msg);
+ }
- int index = -1;
- ke.Handled = true;
+ bool HandleNavKeys (Keys key_data)
+ {
+ if (Items.Count == 0 || !item_control.Visible)
+ return false;
- switch (ke.KeyCode) {
+ if (FocusedItem == null)
+ SetFocusedItem (Items [0]);
+ switch (key_data) {
case Keys.End:
- index = Items.Count - 1;
+ SelectIndex (Items.Count - 1);
break;
case Keys.Home:
- index = 0;
+ SelectIndex (0);
break;
case Keys.Left:
case Keys.Right:
case Keys.Up:
case Keys.Down:
- index = GetAdjustedIndex (ke.KeyCode);
+ SelectIndex (GetAdjustedIndex (key_data));
break;
default:
- ke.Handled = KeySearchString (ke);
- return;
+ return false;
}
-
+
+ return true;
+ }
+
+ void SelectIndex (int index)
+ {
if (index == -1)
return;
if (MultiSelect)
UpdateMultiSelection (index);
- else
+ else if (!items [index].Selected) {
items [index].Selected = true;
+ OnSelectedIndexChanged (EventArgs.Empty);
+ }
SetFocusedItem (items [index]);
EnsureVisible (index);
}
-
+ private void ListView_KeyDown (object sender, KeyEventArgs ke)
+ {
+ if (ke.Handled || Items.Count == 0 || !item_control.Visible)
+ return;
+
+ ke.Handled = KeySearchString (ke);
+ }
+
internal class ItemControl : Control {
ListView owner;
ListViewItem clicked_item;
ListViewItem last_clicked_item;
+ bool hover_processed = false;
+ bool checking = false;
+
+ ListViewLabelEditTextBox edit_text_box;
+ internal ListViewItem edit_item;
+ LabelEditEventArgs edit_args;
public ItemControl (ListView owner)
{
this.owner = owner;
DoubleClick += new EventHandler(ItemsDoubleClick);
- KeyDown += new KeyEventHandler (ItemsKeyDown);
- KeyUp += new KeyEventHandler (ItemsKeyUp);
MouseDown += new MouseEventHandler(ItemsMouseDown);
+ MouseMove += new MouseEventHandler(ItemsMouseMove);
MouseHover += new EventHandler(ItemsMouseHover);
MouseUp += new MouseEventHandler(ItemsMouseUp);
- Paint += new PaintEventHandler (ItemsPaint);
}
void ItemsDoubleClick (object sender, EventArgs e)
owner.ItemActivate (this, e);
}
- void ItemsKeyDown (object sender, KeyEventArgs args)
+ enum BoxSelect {
+ None,
+ Normal,
+ Shift,
+ Control
+ }
+
+ BoxSelect box_select_mode = BoxSelect.None;
+ ArrayList prev_selection;
+ Point box_select_start;
+
+ 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 ()
{
- owner.OnKeyDown (args);
+ 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);
}
- void ItemsKeyUp (object sender, KeyEventArgs args)
+ private Rectangle CalculateBoxSelectRectangle (Point pt)
{
- owner.OnKeyUp (args);
+ 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;
+ }
+ }
+
+ private bool PerformBoxSelection (Point pt)
+ {
+ if (box_select_mode == BoxSelect.None)
+ return false;
+
+ BoxSelectRectangle = CalculateBoxSelectRectangle (pt);
+
+ ArrayList box_items = BoxSelectedItems;
+
+ ArrayList items;
+
+ 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);
+ }
+
+ 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)
Point pt = new Point (me.X, me.Y);
foreach (ListViewItem item in owner.items) {
- if (item.CheckRectReal.Contains (pt)) {
- CheckState curr_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
- item.Checked = !item.Checked;
-
- CheckState new_state = item.Checked ? CheckState.Checked : CheckState.Unchecked;
-
- // Raise the ItemCheck event
- ItemCheckEventArgs ice = new ItemCheckEventArgs (item.Index, curr_state, new_state);
- owner.OnItemCheck (ice);
- break;
+ 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) {
}
}
- owner.SetFocusedItem (clicked_item);
if (clicked_item != null) {
+ owner.SetFocusedItem (clicked_item);
bool changed = !clicked_item.Selected;
- if (owner.MultiSelect && (XplatUI.State.ModifierKeys & Keys.Control) == 0)
+ if (owner.MultiSelect)
owner.UpdateMultiSelection (clicked_item.Index);
else
clicked_item.Selected = true;
// 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 && clicked_item != null)
+ if (me.Clicks > 1) {
owner.OnDoubleClick (EventArgs.Empty);
- else if (me.Clicks == 1 && clicked_item != null)
+ if (owner.CheckBoxes)
+ ToggleCheckState (clicked_item);
+ } else if (me.Clicks == 1) {
owner.OnClick (EventArgs.Empty);
- } else if (owner.selected_indices.Count > 0) {
- // Raise the event if there was at least one item
- // selected and the user click on a dead area (unselecting all)
- owner.SelectedItems.Clear ();
- owner.SelectedIndices.list.Clear ();
- owner.OnSelectedIndexChanged (EventArgs.Empty);
+ if (owner.LabelEdit && !changed)
+ BeginEdit (clicked_item); // this is probably not the correct place to execute BeginEdit
+ }
+ } 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 = owner.SelectedItems.List;
+ } else if (owner.SelectedItems.Count > 0) {
+ owner.SelectedItems.Clear ();
+ owner.OnSelectedIndexChanged (EventArgs.Empty);
+ }
}
}
+ private void ItemsMouseMove (object sender, MouseEventArgs me)
+ {
+ if (PerformBoxSelection (new Point (me.X, me.Y)))
+ return;
+
+ if (owner.HoverSelection && hover_processed) {
+
+ Point pt = PointToClient (Control.MousePosition);
+ ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
+ if (item == null || item.Selected)
+ return;
+
+ hover_processed = false;
+ XplatUI.ResetMouseHover (Handle);
+ }
+ }
+
+
private void ItemsMouseHover (object sender, EventArgs e)
{
- if (Capture || !owner.hover_selection)
+ if (Capture || !owner.HoverSelection)
return;
+ hover_processed = true;
Point pt = PointToClient (Control.MousePosition);
ListViewItem item = owner.GetItemAt (pt.X, pt.Y);
break;
}
}
+ } 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 void LabelEditFinished (object sender, EventArgs e)
+ {
+ EndEdit (edit_item);
+ }
+
+ internal void BeginEdit (ListViewItem item)
+ {
+ if (edit_item != null)
+ EndEdit (edit_item);
+
+ if (edit_text_box == null) {
+ edit_text_box = new ListViewLabelEditTextBox ();
+ edit_text_box.BorderStyle = BorderStyle.FixedSingle;
+ edit_text_box.EditingFinished += new EventHandler (LabelEditFinished);
+ edit_text_box.Visible = false;
+ Controls.Add (edit_text_box);
+ }
+
+ item.EnsureVisible();
+
+ edit_text_box.Reset ();
+
+ switch (owner.view) {
+ case View.List:
+ case View.SmallIcon:
+ case View.Details:
+ edit_text_box.TextAlign = HorizontalAlignment.Left;
+ edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
+ SizeF sizef = DeviceContext.MeasureString (item.Text, item.Font);
+ edit_text_box.Width = (int)sizef.Width + 4;
+ edit_text_box.MaxWidth = owner.ClientRectangle.Width - edit_text_box.Bounds.X;
+ edit_text_box.WordWrap = false;
+ edit_text_box.Multiline = false;
+ break;
+ case View.LargeIcon:
+ edit_text_box.TextAlign = HorizontalAlignment.Center;
+ edit_text_box.Bounds = item.GetBounds (ItemBoundsPortion.Label);
+ sizef = DeviceContext.MeasureString (item.Text, item.Font);
+ edit_text_box.Width = (int)sizef.Width + 4;
+ edit_text_box.MaxWidth = item.GetBounds(ItemBoundsPortion.Entire).Width;
+ edit_text_box.MaxHeight = owner.ClientRectangle.Height - edit_text_box.Bounds.Y;
+ edit_text_box.WordWrap = true;
+ edit_text_box.Multiline = true;
+ break;
+ }
+
+ edit_text_box.Text = item.Text;
+ edit_text_box.Font = item.Font;
+ edit_text_box.Visible = true;
+ edit_text_box.Focus ();
+ edit_text_box.SelectAll ();
+
+ edit_args = new LabelEditEventArgs (owner.Items.IndexOf(edit_item));
+ owner.OnBeforeLabelEdit (edit_args);
+
+ if (edit_args.CancelEdit)
+ EndEdit (item);
+
+ edit_item = item;
+ }
+
+ internal void EndEdit (ListViewItem item)
+ {
+ if (edit_text_box != null && edit_text_box.Visible) {
+ edit_text_box.Visible = false;
+ }
+
+ if (edit_item != null && edit_item == item) {
+ owner.OnAfterLabelEdit (edit_args);
+
+ if (!edit_args.CancelEdit) {
+ if (edit_args.Label != null)
+ edit_item.Text = edit_args.Label;
+ else
+ edit_item.Text = edit_text_box.Text;
+ }
+
+ }
+
+
+ edit_item = null;
}
- private void ItemsPaint (object sender, PaintEventArgs pe)
+ internal override void OnPaintInternal (PaintEventArgs pe)
{
ThemeEngine.Current.DrawListViewItems (pe.Graphics, pe.ClipRectangle, owner);
}
+
+ internal override void OnGotFocusInternal (EventArgs e)
+ {
+ owner.Focus ();
+ }
+ }
+
+ internal class ListViewLabelEditTextBox : TextBox
+ {
+ int max_width = -1;
+ int min_width = -1;
+
+ int max_height = -1;
+ int min_height = -1;
+
+ int old_number_lines = 1;
+
+ SizeF text_size_one_char;
+
+ public ListViewLabelEditTextBox ()
+ {
+ min_height = DefaultSize.Height;
+ text_size_one_char = DeviceContext.MeasureString ("B", Font);
+ }
+
+ public int MaxWidth {
+ set {
+ if (value < min_width)
+ max_width = min_width;
+ else
+ max_width = value;
+ }
+ }
+
+ public int MaxHeight {
+ set {
+ if (value < min_height)
+ max_height = min_height;
+ else
+ max_height = value;
+ }
+ }
+
+ public new int Width {
+ get {
+ return base.Width;
+ }
+ set {
+ min_width = value;
+ base.Width = value;
+ }
+ }
+
+ public override Font Font {
+ get {
+ return base.Font;
+ }
+ set {
+ base.Font = value;
+ text_size_one_char = DeviceContext.MeasureString ("B", Font);
+ }
+ }
+
+ protected override void OnTextChanged (EventArgs e)
+ {
+ SizeF text_size = DeviceContext.MeasureString (Text, Font);
+
+ int new_width = (int)text_size.Width + 8;
+
+ if (!Multiline)
+ ResizeTextBoxWidth (new_width);
+ else {
+ if (Width != max_width)
+ ResizeTextBoxWidth (new_width);
+
+ int number_lines = Lines.Length;
+
+ if (number_lines != old_number_lines) {
+ int new_height = number_lines * (int)text_size_one_char.Height + 4;
+ old_number_lines = number_lines;
+
+ ResizeTextBoxHeight (new_height);
+ }
+ }
+
+ base.OnTextChanged (e);
+ }
+
+ protected override bool IsInputKey (Keys key_data)
+ {
+ if ((key_data & Keys.Alt) == 0) {
+ switch (key_data & Keys.KeyCode) {
+ case Keys.Enter:
+ return true;
+ }
+ }
+ return base.IsInputKey (key_data);
+ }
+
+ protected override void OnKeyDown (KeyEventArgs e)
+ {
+ if (e.KeyCode == Keys.Return && Visible) {
+ this.Visible = false;
+ OnEditingFinished (e);
+ }
+ }
+
+ protected override void OnLostFocus (EventArgs e)
+ {
+ if (Visible) {
+ OnEditingFinished (e);
+ }
+ }
+
+ protected void OnEditingFinished (EventArgs e)
+ {
+ if (EditingFinished != null)
+ EditingFinished (this, EventArgs.Empty);
+ }
+
+ private void ResizeTextBoxWidth (int new_width)
+ {
+ if (new_width > max_width)
+ base.Width = max_width;
+ else
+ if (new_width >= min_width)
+ base.Width = new_width;
+ else
+ base.Width = min_width;
+ }
+
+ private void ResizeTextBoxHeight (int new_height)
+ {
+ if (new_height > max_height)
+ base.Height = max_height;
+ else
+ if (new_height >= min_height)
+ base.Height = new_height;
+ else
+ base.Height = min_height;
+ }
+
+ public void Reset ()
+ {
+ max_width = -1;
+ min_width = -1;
+
+ max_height = -1;
+
+ old_number_lines = 1;
+
+ Text = String.Empty;
+
+ Size = DefaultSize;
+ }
+
+ public event EventHandler EditingFinished;
}
- private void ListView_Paint (object sender, PaintEventArgs pe)
+ internal override void OnPaintInternal (PaintEventArgs pe)
{
- if (Width <= 0 || Height <= 0 || !Visible || updating)
+ if (updating)
return;
CalculateScrollBars ();
}
+ void FocusChanged (object o, EventArgs args)
+ {
+ if (Items.Count == 0)
+ return;
+
+ 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)
{
CalculateListView (alignment);
private void HorizontalScroller (object sender, EventArgs e)
{
+ item_control.EndEdit (item_control.edit_item);
+
// Avoid unnecessary flickering, when button is
// kept pressed at the end
if (h_marker != h_scroll.Value) {
private void VerticalScroller (object sender, EventArgs e)
{
+ item_control.EndEdit (item_control.edit_item);
+
// Avoid unnecessary flickering, when button is
// kept pressed at the end
if (v_marker != v_scroll.Value) {
protected override void CreateHandle ()
{
base.CreateHandle ();
+ for (int i = 0; i < SelectedItems.Count; i++)
+ OnSelectedIndexChanged (EventArgs.Empty);
}
protected override void Dispose (bool disposing)
protected override void OnHandleCreated (EventArgs e)
{
base.OnHandleCreated (e);
- SuspendLayout ();
- Controls.AddImplicit (header_control);
- Controls.AddImplicit (item_control);
- Controls.AddImplicit (this.v_scroll);
- Controls.AddImplicit (this.h_scroll);
- ResumeLayout ();
+ Sort ();
}
protected override void OnHandleDestroyed (EventArgs e)
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.Sort (item_sorter);
+ if (redraw)
+ this.Redraw (true);
}
public override string ToString ()
MouseDown += new MouseEventHandler (HeaderMouseDown);
MouseMove += new MouseEventHandler (HeaderMouseMove);
MouseUp += new MouseEventHandler (HeaderMouseUp);
- Paint += new PaintEventHandler (HeaderPaint);
}
private ColumnHeader ColumnAtX (int x)
Capture = true;
if (owner.AllowColumnReorder) {
drag_x = me.X;
- drag_column = (ColumnHeader) clicked_column.Clone ();
+ drag_column = (ColumnHeader) (clicked_column as ICloneable).Clone ();
drag_column.column_rect = clicked_column.Rect;
drag_to_index = GetReorderedIndex (clicked_column);
}
int x = me.X + owner.h_marker;
ColumnHeader over = ColumnAtX (x);
- if (x < over.X + over.Width / 2)
+ 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;
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;
}
clicked_column = null;
}
- void HeaderPaint (object sender, PaintEventArgs pe)
+ internal override void OnPaintInternal (PaintEventArgs pe)
{
- if (Width <= 0 || Height <= 0 || !Visible || owner.updating)
+ if (owner.updating)
return;
Theme theme = ThemeEngine.Current;
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 ()
+ {
+ ArrayList checked_items = owner.CheckedItems.List;
+ int [] indices = new int [checked_items.Count];
+ for (int i = 0; i < checked_items.Count; i++) {
+ ListViewItem item = (ListViewItem) checked_items [i];
+ indices [i] = item.Index;
+ }
+ return indices;
+ }
} // CheckedIndexCollection
public class CheckedListViewItemCollection : IList, ICollection, IEnumerable
{
- internal ArrayList list;
- private ListView owner;
+ private readonly ListView owner;
+ private ArrayList list;
#region Public Constructor
public CheckedListViewItemCollection (ListView owner)
{
- list = new ArrayList ();
this.owner = owner;
+ this.owner.Items.Changed += new CollectionChangedHandler (
+ ItemsCollection_Changed);
}
#endregion // Public Constructor
#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.");
- return (ListViewItem) list [index];
+ ArrayList checked_items = List;
+ if (index < 0 || index >= checked_items.Count)
+ throw new ArgumentOutOfRangeException ("index");
+ return (ListViewItem) checked_items [index];
}
}
bool ICollection.IsSynchronized {
- get { return list.IsSynchronized; }
+ get { return false; }
}
object ICollection.SyncRoot {
#region Public Methods
public bool Contains (ListViewItem item)
{
- return list.Contains (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)
{
- list.CopyTo (dest, index);
+ if (!owner.CheckBoxes)
+ return;
+ List.CopyTo (dest, index);
}
- public virtual IEnumerator GetEnumerator ()
+ public IEnumerator GetEnumerator ()
{
- return list.GetEnumerator ();
+ if (!owner.CheckBoxes)
+ return (new ListViewItem [0]).GetEnumerator ();
+ return List.GetEnumerator ();
}
int IList.Add (object value)
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)
{
- return list.IndexOf (item);
+ if (!owner.CheckBoxes)
+ return -1;
+ return List.IndexOf (item);
}
#endregion // Public Methods
+ internal ArrayList List {
+ get {
+ if (list == null) {
+ list = new ArrayList ();
+ foreach (ListViewItem item in owner.Items) {
+ if (item.Checked)
+ list.Add (item);
+ }
+ }
+ return list;
+ }
+ }
+
+ internal void Reset ()
+ {
+ // force re-population of list
+ list = null;
+ }
+
+ private void ItemsCollection_Changed ()
+ {
+ Reset ();
+ }
} // 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 ArrayList list;
+ 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 = owner;
list [displayIndex] = value;
+ OnChange ();
owner.Redraw (true);
}
this [index] = (ListViewItem) value;
else
this [index] = new ListViewItem (value.ToString ());
+ OnChange ();
}
}
#endregion // Public Properties
value.Owner = owner;
list.Add (value);
- if (owner.Sorting != SortOrder.None)
- owner.Sort ();
-
+ owner.Sort (false);
+ OnChange ();
owner.Redraw (true);
-
return value;
}
public void AddRange (ListViewItem [] values)
{
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 = owner;
list.Add (item);
}
- if (owner.Sorting != SortOrder.None)
- owner.Sort ();
-
+ owner.Sort (false);
+ OnChange ();
owner.Redraw (true);
}
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 ();
+ OnChange ();
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 ();
}
li.Owner = owner;
result = list.Add (li);
+ OnChange ();
owner.Redraw (true);
return result;
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 = owner;
list.Insert (index, item);
+ OnChange ();
owner.Redraw (true);
return item;
}
if (!list.Contains (item))
return;
- owner.SelectedItems.list.Remove (item);
- owner.SelectedIndices.list.Remove (item.Index);
- owner.CheckedItems.list.Remove (item);
- owner.CheckedIndices.list.Remove (item.Index);
+ bool selection_changed = owner.SelectedItems.Contains (item);
list.Remove (item);
+ OnChange ();
owner.Redraw (true);
+ if (selection_changed)
+ owner.OnSelectedIndexChanged (EventArgs.Empty);
}
public virtual void RemoveAt (int index)
{
- if (index < 0 || index >= list.Count)
- throw new ArgumentOutOfRangeException ("Index out of range.");
-
+ if (index < 0 || index >= Count)
+ throw new ArgumentOutOfRangeException ("index");
+ bool selection_changed = owner.SelectedIndices.Contains (index);
list.RemoveAt (index);
- owner.SelectedItems.list.RemoveAt (index);
- owner.SelectedIndices.list.RemoveAt (index);
- owner.CheckedItems.list.RemoveAt (index);
- owner.CheckedIndices.list.RemoveAt (index);
+ OnChange ();
owner.Redraw (false);
+ if (selection_changed)
+ owner.OnSelectedIndexChanged (EventArgs.Empty);
}
#endregion // Public Methods
+ internal event CollectionChangedHandler Changed;
+
+ internal void Sort (IComparer comparer)
+ {
+ list.Sort (comparer);
+ OnChange ();
+ }
+
+ internal void OnChange ()
+ {
+ if (Changed != null)
+ Changed ();
+ }
} // ListViewItemCollection
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 ()
+ {
+ ArrayList selected_items = owner.SelectedItems.List;
+ int [] indices = new int [selected_items.Count];
+ for (int i = 0; i < selected_items.Count; i++) {
+ ListViewItem item = (ListViewItem) selected_items [i];
+ indices [i] = item.Index;
+ }
+ return indices;
+ }
} // SelectedIndexCollection
public class SelectedListViewItemCollection : IList, ICollection, IEnumerable
{
- internal ArrayList list;
- private ListView owner;
+ private readonly ListView owner;
+ private ArrayList list;
#region Public Constructor
public SelectedListViewItemCollection (ListView owner)
{
- list = new ArrayList ();
this.owner = owner;
+ this.owner.Items.Changed += new CollectionChangedHandler (
+ ItemsCollection_Changed);
}
#endregion // Public Constructor
#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.");
- return (ListViewItem) list [index];
+ ArrayList selected_items = List;
+ if (!owner.IsHandleCreated || index < 0 || index >= selected_items.Count)
+ throw new ArgumentOutOfRangeException ("index");
+ return (ListViewItem) selected_items [index];
}
}
bool ICollection.IsSynchronized {
- get { return list.IsSynchronized; }
+ get { return false; }
}
object ICollection.SyncRoot {
#endregion // Public Properties
#region Public Methods
- public virtual void Clear ()
+ public void Clear ()
{
- ArrayList copy = (ArrayList) list.Clone ();
- for (int i = 0; i < copy.Count; i++)
- ((ListViewItem) copy [i]).Selected = false;
+ if (!owner.IsHandleCreated)
+ return;
- list.Clear ();
+ foreach (ListViewItem item in List)
+ item.Selected = false;
}
public bool Contains (ListViewItem item)
{
- return list.Contains (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)
{
- list.CopyTo (dest, index);
+ if (!owner.IsHandleCreated)
+ return;
+ List.CopyTo (dest, index);
}
- public virtual IEnumerator GetEnumerator ()
+ public IEnumerator GetEnumerator ()
{
- return list.GetEnumerator ();
+ if (!owner.IsHandleCreated)
+ return (new ListViewItem [0]).GetEnumerator ();
+ return List.GetEnumerator ();
}
int IList.Add (object value)
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)
{
- return list.IndexOf (item);
+ if (!owner.IsHandleCreated)
+ return -1;
+ return List.IndexOf (item);
}
#endregion // Public Methods
+ internal ArrayList List {
+ get {
+ if (list == null) {
+ list = new ArrayList ();
+ foreach (ListViewItem item in owner.Items) {
+ if (item.Selected)
+ list.Add (item);
+ }
+ }
+ return list;
+ }
+ }
+
+ internal void Reset ()
+ {
+ // force re-population of list
+ list = null;
+ }
+
+ private void ItemsCollection_Changed ()
+ {
+ Reset ();
+ }
} // SelectedListViewItemCollection
+ internal delegate void CollectionChangedHandler ();
+
#endregion // Subclasses
}
}