|
//------------------------------------------------------------------------------
// <copyright file="ListViewItem.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
//------------------------------------------------------------------------------
/*
*/
namespace System.Windows.Forms {
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Security;
using System.Security.Permissions;
using System;
using System.Drawing;
using System.Drawing.Design;
using System.ComponentModel;
using System.IO;
using Microsoft.Win32;
using System.Collections;
using System.Collections.Specialized;
using System.Runtime.Remoting;
using System.Runtime.InteropServices;
using System.ComponentModel.Design.Serialization;
using System.Reflection;
using System.Globalization;
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem"]/*' />
/// <devdoc>
/// <para>
/// Implements an item of a <see cref='System.Windows.Forms.ListView'/>.
/// </para>
/// </devdoc>
[
TypeConverterAttribute(typeof(ListViewItemConverter)),
ToolboxItem(false),
DesignTimeVisible(false),
DefaultProperty("Text"),
Serializable,
SuppressMessage("Microsoft.Usage", "CA2240:ImplementISerializableCorrectly")
]
public class ListViewItem : ICloneable, ISerializable {
private const int MAX_SUBITEMS = 4096;
private static readonly BitVector32.Section StateSelectedSection = BitVector32.CreateSection(1);
private static readonly BitVector32.Section StateImageMaskSet = BitVector32.CreateSection(1, StateSelectedSection);
private static readonly BitVector32.Section StateWholeRowOneStyleSection = BitVector32.CreateSection(1, StateImageMaskSet);
private static readonly BitVector32.Section SavedStateImageIndexSection = BitVector32.CreateSection(15, StateWholeRowOneStyleSection);
private static readonly BitVector32.Section SubItemCountSection = BitVector32.CreateSection(MAX_SUBITEMS, SavedStateImageIndexSection);
private int indentCount = 0;
private Point position = new Point(-1,-1);
internal ListView listView;
internal ListViewGroup group;
private string groupName;
private ListViewSubItemCollection listViewSubItemCollection = null;
private ListViewSubItem[] subItems;
// we stash the last index we got as a seed to GetDisplayIndex.
private int lastIndex = -1;
// An ID unique relative to a given list view that comctl uses to identify items.
internal int ID = -1;
private BitVector32 state = new BitVector32();
private ListViewItemImageIndexer imageIndexer;
private String toolTipText = String.Empty;
object userData;
// We need a special way to defer to the ListView's image
// list for indexing purposes.
internal class ListViewItemImageIndexer : ImageList.Indexer {
private ListViewItem owner;
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ImageListType.ListViewItemImageIndexer"]/*' />
public ListViewItemImageIndexer(ListViewItem item) {
owner = item;
}
public override ImageList ImageList {
get {
if (owner != null) {
return owner.ImageList;
}
return null;
}
set { Debug.Assert(false, "We should never set the image list"); }
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem() {
StateSelected = false;
UseItemStyleForSubItems = true;
SavedStateImageIndex = -1;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem1"]/*' />
/// <devdoc>
/// Creates a ListViewItem object from an Stream.
/// The Serialization constructor is protected, as per FxCop Microsoft.Usage, CA2229 Rule.
/// </devdoc>
[
SuppressMessage("Microsoft.Usage", "CA2214:DoNotCallOverridableMethodsInConstructors") // Changing Deserialize to be non-virtual
// would be a breaking change.
]
protected ListViewItem(SerializationInfo info, StreamingContext context) : this() {
Deserialize(info, context);
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem2"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string text) : this(text, -1) {
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem3"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string text, int imageIndex) : this() {
this.ImageIndexer.Index = imageIndex;
Text = text;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem4"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items) : this(items, -1) {
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem5"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items, int imageIndex) : this() {
this.ImageIndexer.Index = imageIndex;
if (items != null && items.Length > 0) {
this.subItems = new ListViewSubItem[items.Length];
for (int i = 0; i < items.Length; i++) {
subItems[i] = new ListViewSubItem(this, items[i]);
}
this.SubItemCount = items.Length;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem6"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items, int imageIndex, Color foreColor, Color backColor, Font font) : this(items, imageIndex) {
this.ForeColor = foreColor;
this.BackColor = backColor;
this.Font = font;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem7"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(ListViewSubItem[] subItems, int imageIndex) : this() {
this.ImageIndexer.Index = imageIndex;
this.subItems = subItems;
this.SubItemCount = this.subItems.Length;
// Update the owner of these subitems
//
for(int i=0; i < subItems.Length; ++i) {
subItems[i].owner = this;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem8"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(ListViewGroup group) : this() {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem9"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string text, ListViewGroup group) : this(text) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem10"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string text, int imageIndex, ListViewGroup group) : this(text, imageIndex) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem11"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items, ListViewGroup group) : this(items) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem12"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items, int imageIndex, ListViewGroup group) : this(items, imageIndex) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem13"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items, int imageIndex, Color foreColor, Color backColor, Font font, ListViewGroup group) :
this(items, imageIndex, foreColor, backColor, font) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem14"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(ListViewSubItem[] subItems, int imageIndex, ListViewGroup group) : this(subItems, imageIndex) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem15"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string text, string imageKey) : this() {
this.ImageIndexer.Key = imageKey;
Text = text;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem16"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items, string imageKey) : this() {
this.ImageIndexer.Key = imageKey;
if (items != null && items.Length > 0) {
this.subItems = new ListViewSubItem[items.Length];
for (int i = 0; i < items.Length; i++) {
subItems[i] = new ListViewSubItem(this, items[i]);
}
this.SubItemCount = items.Length;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem17"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items, string imageKey, Color foreColor, Color backColor, Font font) : this(items, imageKey) {
this.ForeColor = foreColor;
this.BackColor = backColor;
this.Font = font;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem18"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(ListViewSubItem[] subItems, string imageKey) : this() {
this.ImageIndexer.Key = imageKey;
this.subItems = subItems;
this.SubItemCount = this.subItems.Length;
// Update the owner of these subitems
//
for(int i=0; i < subItems.Length; ++i) {
subItems[i].owner = this;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem19"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string text, string imageKey, ListViewGroup group) : this(text, imageKey) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem20"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items, string imageKey, ListViewGroup group) : this(items, imageKey) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem21"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(string[] items, string imageKey, Color foreColor, Color backColor, Font font, ListViewGroup group) :
this(items, imageKey, foreColor, backColor, font) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewItem22"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewItem(ListViewSubItem[] subItems, string imageKey, ListViewGroup group) : this(subItems, imageKey) {
this.Group = group;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.BackColor"]/*' />
/// <devdoc>
/// The font that this item will be displayed in. If its value is null, it will be displayed
/// using the global font for the ListView control that hosts it.
/// </devdoc>
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRCategory(SR.CatAppearance)
]
public Color BackColor {
get {
if (SubItemCount == 0) {
if (listView != null) {
return listView.BackColor;
}
return SystemColors.Window;
}
else {
return subItems[0].BackColor;
}
}
set {
SubItems[0].BackColor = value;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Bounds"]/*' />
/// <devdoc>
/// Returns the ListViewItem's bounding rectangle, including subitems. The bounding rectangle is empty if
/// the ListViewItem has not been added to a ListView control.
/// </devdoc>
[Browsable(false)]
public Rectangle Bounds {
get {
if (listView != null) {
return listView.GetItemRect(Index);
}
else
return new Rectangle();
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Checked"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
DefaultValue(false),
RefreshPropertiesAttribute(RefreshProperties.Repaint),
SRCategory(SR.CatAppearance)
]
public bool Checked {
get {
return StateImageIndex > 0;
}
set {
if (Checked != value) {
if (listView != null && listView.IsHandleCreated) {
StateImageIndex = value ? 1 : 0;
// the setter for StateImageIndex calls ItemChecked handler
// thus need to verify validity of the listView again
if ((this.listView != null) && !this.listView.UseCompatibleStateImageBehavior) {
if (!listView.CheckBoxes) {
listView.UpdateSavedCheckedItems(this, value);
}
}
}
else {
SavedStateImageIndex = value ? 1 : 0;
}
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Focused"]/*' />
/// <devdoc>
/// Returns the focus state of the ListViewItem.
/// </devdoc>
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false)
]
public bool Focused {
get {
if (listView != null && listView.IsHandleCreated) {
return(listView.GetItemState(Index, NativeMethods.LVIS_FOCUSED) != 0);
}
else return false;
}
set {
if (listView != null && listView.IsHandleCreated) {
listView.SetItemState(Index, value ? NativeMethods.LVIS_FOCUSED : 0, NativeMethods.LVIS_FOCUSED);
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Font"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
Localizable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRCategory(SR.CatAppearance)
]
public Font Font {
get {
if (SubItemCount == 0) {
if (listView != null) {
return listView.Font;
}
return Control.DefaultFont;
}
else {
return subItems[0].Font;
}
}
set {
SubItems[0].Font = value;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ForeColor"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRCategory(SR.CatAppearance)
]
public Color ForeColor {
get {
if (SubItemCount == 0) {
if (listView != null) {
return listView.ForeColor;
}
return SystemColors.WindowText;
}
else {
return subItems[0].ForeColor;
}
}
set {
SubItems[0].ForeColor = value;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Group"]/*' />
/// <devdoc>
/// <para>The group to which this item belongs</para>
/// </devdoc>
[
DefaultValue(null),
Localizable(true),
SRCategory(SR.CatBehavior)
]
public ListViewGroup Group {
get
{
return group;
}
set
{
if (group != value) {
if (value != null) {
value.Items.Add(this);
}
else {
group.Items.Remove(this);
}
}
Debug.Assert(this.group == value, "BUG: group member variable wasn't updated!");
// If the user specifically sets the group then don't use the groupName again.
this.groupName = null;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ImageIndex"]/*' />
/// <devdoc>
/// Returns the ListViewItem's currently set image index
/// </devdoc>
[
DefaultValue(-1),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
Localizable(true),
RefreshProperties(RefreshProperties.Repaint),
SRCategory(SR.CatBehavior),
SRDescription(SR.ListViewItemImageIndexDescr),
TypeConverterAttribute(typeof(NoneExcludedImageIndexConverter))
]
public int ImageIndex {
get {
if (ImageIndexer.Index != -1 && ImageList != null && ImageIndexer.Index >= ImageList.Images.Count) {
return ImageList.Images.Count - 1;
}
return this.ImageIndexer.Index;
}
set {
if (value < -1) {
throw new ArgumentOutOfRangeException("ImageIndex", SR.GetString(SR.InvalidLowBoundArgumentEx, "ImageIndex", value.ToString(CultureInfo.CurrentCulture), (-1).ToString(CultureInfo.CurrentCulture)));
}
ImageIndexer.Index = value;
if (listView != null && listView.IsHandleCreated) {
listView.SetItemImage(Index, ImageIndexer.ActualIndex);
}
}
}
internal ListViewItemImageIndexer ImageIndexer {
get {
if (imageIndexer == null) {
imageIndexer = new ListViewItemImageIndexer(this);
}
return imageIndexer;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ImageIndex"]/*' />
/// <devdoc>
/// Returns the ListViewItem's currently set image index
/// </devdoc>
[
DefaultValue(""),
TypeConverterAttribute(typeof(ImageKeyConverter)),
Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
RefreshProperties(RefreshProperties.Repaint),
SRCategory(SR.CatBehavior),
Localizable(true)
]
public string ImageKey {
get {
return this.ImageIndexer.Key;
}
set {
ImageIndexer.Key = value;
if (listView != null && listView.IsHandleCreated) {
listView.SetItemImage(Index, ImageIndexer.ActualIndex);
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ImageList"]/*' />
[Browsable(false)]
public ImageList ImageList {
get {
if (listView != null) {
switch(listView.View) {
case View.LargeIcon:
case View.Tile:
return listView.LargeImageList;
case View.SmallIcon:
case View.Details:
case View.List:
return listView.SmallImageList;
}
}
return null;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.IndentCount"]/*' />
[
DefaultValue(0),
SRDescription(SR.ListViewItemIndentCountDescr),
SRCategory(SR.CatDisplay)
]
public int IndentCount {
get {
return indentCount;
}
set {
if (value == indentCount)
return;
if (value < 0) {
throw new ArgumentOutOfRangeException("IndentCount", SR.GetString(SR.ListViewIndentCountCantBeNegative));
}
indentCount = value;
if (listView != null && listView.IsHandleCreated) {
listView.SetItemIndentCount(Index, indentCount);
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Index"]/*' />
/// <devdoc>
/// Returns ListViewItem's current index in the listview, or -1 if it has not been added to a ListView control.
/// </devdoc>
[Browsable(false)]
public int Index {
get {
if (listView != null) {
// if the list is virtual, the ComCtrl control does not keep any information
// about any list view items, so we use our cache instead.
if (!listView.VirtualMode) {
lastIndex = listView.GetDisplayIndex(this, lastIndex);
}
return lastIndex;
}
else {
return -1;
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListView"]/*' />
/// <devdoc>
/// Returns the ListView control that holds this ListViewItem. May be null if no
/// control has been assigned yet.
/// </devdoc>
[Browsable(false)]
public ListView ListView {
get {
return listView;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Name"]/*' />
/// <devdoc>
/// Name associated with this ListViewItem
/// </devdoc>
[
Localizable(true),
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public string Name {
get {
if (SubItemCount == 0) {
return string.Empty;
}
else {
return subItems[0].Name;
}
}
set {
SubItems[0].Name = value;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Position"]/*' />
[
SRCategory(SR.CatDisplay),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
Browsable(false)
]
public Point Position {
get {
if (listView != null && listView.IsHandleCreated) {
position = listView.GetItemPosition(Index);
}
return position;
}
set {
if (value.Equals(position))
return;
position = value;
if (listView != null && listView.IsHandleCreated) {
if (!listView.VirtualMode) {
listView.SetItemPosition(Index, position.X, position.Y);
}
}
}
}
// the listView needs the raw encoding for the state image index when in VirtualMode
internal int RawStateImageIndex {
get {
return (this.SavedStateImageIndex + 1) << 12;
}
}
/// <devdoc>
/// Accessor for our state bit vector.
/// </devdoc>
private int SavedStateImageIndex {
get {
// State goes from zero to 15, but we need a negative
// number, so we store + 1.
return state[SavedStateImageIndexSection] - 1;
}
set {
// flag whether we've set a value.
//
state[StateImageMaskSet] = (value == -1 ? 0 : 1);
// push in the actual value
//
state[SavedStateImageIndexSection] = value + 1;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Selected"]/*' />
/// <devdoc>
/// Treats the ListViewItem as a row of strings, and returns an array of those strings
/// </devdoc>
[
Browsable(false),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)
]
public bool Selected {
get {
if (listView != null && listView.IsHandleCreated) {
return(listView.GetItemState(Index, NativeMethods.LVIS_SELECTED) != 0);
}
else
return StateSelected;
}
set {
if (listView != null && listView.IsHandleCreated) {
listView.SetItemState(Index, value ? NativeMethods.LVIS_SELECTED: 0, NativeMethods.LVIS_SELECTED);
// vsw 451976: update comctl32's selection information.
listView.SetSelectionMark(Index);
}
else {
StateSelected = value;
if (this.listView != null && this.listView.IsHandleCreated) {
// APPCOMPAT: set the selected state on the list view item only if the list view's Handle is already created.
// vsw 448052.
listView.CacheSelectedStateForItem(this, value);
}
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.StateImageIndex"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
Localizable(true),
TypeConverterAttribute(typeof(NoneExcludedImageIndexConverter)),
DefaultValue(-1),
SRDescription(SR.ListViewItemStateImageIndexDescr),
SRCategory(SR.CatBehavior),
RefreshProperties(RefreshProperties.Repaint),
Editor("System.Windows.Forms.Design.ImageIndexEditor, " + AssemblyRef.SystemDesign, typeof(UITypeEditor)),
RelatedImageList("ListView.StateImageList")
]
public int StateImageIndex {
get {
if (listView != null && listView.IsHandleCreated) {
int state = listView.GetItemState(Index, NativeMethods.LVIS_STATEIMAGEMASK);
return ((state >> 12) - 1); // index is 1-based
}
else return SavedStateImageIndex;
}
set {
if (value < -1 || value > 14)
throw new ArgumentOutOfRangeException("StateImageIndex", SR.GetString(SR.InvalidArgument, "StateImageIndex", (value).ToString(CultureInfo.CurrentCulture)));
if (listView != null && listView.IsHandleCreated) {
this.state[StateImageMaskSet] = (value == -1 ? 0 : 1);
int state = ((value + 1) << 12); // index is 1-based
listView.SetItemState(Index, state, NativeMethods.LVIS_STATEIMAGEMASK);
}
SavedStateImageIndex = value;
}
}
internal bool StateImageSet {
get {
return (this.state[StateImageMaskSet] != 0);
}
}
/// <devdoc>
/// Accessor for our state bit vector.
/// </devdoc>
internal bool StateSelected {
get {
return state[StateSelectedSection] == 1;
}
set {
state[StateSelectedSection] = value ? 1 : 0;
}
}
/// <devdoc>
/// Accessor for our state bit vector.
/// </devdoc>
private int SubItemCount {
get {
return state[SubItemCountSection];
}
set {
state[SubItemCountSection] = value;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.SubItems"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
SRCategory(SR.CatData),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRDescription(SR.ListViewItemSubItemsDescr),
Editor("System.Windows.Forms.Design.ListViewSubItemCollectionEditor, " + AssemblyRef.SystemDesign,typeof(UITypeEditor)),
]
public ListViewSubItemCollection SubItems {
get {
if (SubItemCount == 0) {
subItems = new ListViewSubItem[1];
subItems[0] = new ListViewSubItem(this, string.Empty);
SubItemCount = 1;
}
if (listViewSubItemCollection == null) {
listViewSubItemCollection = new ListViewSubItemCollection(this);
}
return listViewSubItemCollection;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Tag"]/*' />
[
SRCategory(SR.CatData),
Localizable(false),
Bindable(true),
SRDescription(SR.ControlTagDescr),
DefaultValue(null),
TypeConverter(typeof(StringConverter)),
]
public object Tag {
get {
return userData;
}
set {
userData = value;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Text"]/*' />
/// <devdoc>
/// Text associated with this ListViewItem
/// </devdoc>
[
Localizable(true),
DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
SRCategory(SR.CatAppearance)
]
public string Text {
get {
if (SubItemCount == 0) {
return string.Empty;
}
else {
return subItems[0].Text;
}
}
set {
SubItems[0].Text = value;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ToolTipText"]/*' />
/// <devdoc>
/// Tool tip text associated with this ListViewItem
/// </devdoc>
[
SRCategory(SR.CatAppearance),
DefaultValue("")
]
public string ToolTipText {
get {
return toolTipText;
}
set {
if (value == null)
value = String.Empty;
if (WindowsFormsUtils.SafeCompareStrings(toolTipText, value, false /*ignoreCase*/)) {
return;
}
toolTipText = value;
// tell the list view about this change
if (this.listView != null && this.listView.IsHandleCreated) {
this.listView.ListViewItemToolTipChanged(this);
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.UseItemStyleForSubItems"]/*' />
/// <devdoc>
/// Whether or not the font and coloring for the ListViewItem will be used for all of its subitems.
/// If true, the ListViewItem style will be used when drawing the subitems.
/// If false, the ListViewItem and its subitems will be drawn in their own individual styles
/// if any have been set.
/// </devdoc>
[
DefaultValue(true),
SRCategory(SR.CatAppearance)
]
public bool UseItemStyleForSubItems {
get {
return state[StateWholeRowOneStyleSection] == 1;
}
set {
state[StateWholeRowOneStyleSection] = value ? 1 : 0;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.BeginEdit"]/*' />
/// <devdoc>
/// Initiate editing of the item's label.
/// Only effective if LabelEdit property is true.
/// </devdoc>
public void BeginEdit() {
if (Index >= 0) {
ListView lv = ListView;
if (lv.LabelEdit == false)
throw new InvalidOperationException(SR.GetString(SR.ListViewBeginEditFailed));
if (!lv.Focused)
lv.FocusInternal();
UnsafeNativeMethods.SendMessage(new HandleRef(lv, lv.Handle), NativeMethods.LVM_EDITLABEL, Index, 0);
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Clone"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public virtual object Clone() {
ListViewSubItem[] clonedSubItems = new ListViewSubItem[this.SubItems.Count];
for(int index=0; index < this.SubItems.Count; ++index) {
ListViewSubItem subItem = this.SubItems[index];
clonedSubItems[index] = new ListViewSubItem(null,
subItem.Text,
subItem.ForeColor,
subItem.BackColor,
subItem.Font);
clonedSubItems[index].Tag = subItem.Tag;
}
Type clonedType = this.GetType();
ListViewItem newItem = null;
if (clonedType == typeof(ListViewItem)) {
newItem = new ListViewItem(clonedSubItems, this.ImageIndexer.Index);
}
else {
// SECREVIEW : Late-binding does not represent a security thread, see bug#411899 for more info..
//
newItem = (ListViewItem)Activator.CreateInstance(clonedType);
}
newItem.subItems = clonedSubItems;
newItem.ImageIndexer.Index = this.ImageIndexer.Index;
newItem.SubItemCount = this.SubItemCount;
newItem.Checked = this.Checked;
newItem.UseItemStyleForSubItems = this.UseItemStyleForSubItems;
newItem.Tag = this.Tag;
// Only copy over the ImageKey if we're using it.
if (!String.IsNullOrEmpty(this.ImageIndexer.Key)) {
newItem.ImageIndexer.Key = this.ImageIndexer.Key;
}
newItem.indentCount = this.indentCount;
newItem.StateImageIndex = this.StateImageIndex;
newItem.toolTipText = this.toolTipText;
newItem.BackColor = this.BackColor;
newItem.ForeColor = this.ForeColor;
newItem.Font = this.Font;
newItem.Text = this.Text;
newItem.Group = this.Group;
return newItem;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.EnsureVisible"]/*' />
/// <devdoc>
/// Ensure that the item is visible, scrolling the view as necessary.
/// </devdoc>
public virtual void EnsureVisible() {
if (listView != null && listView.IsHandleCreated) {
listView.EnsureVisible(Index);
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.FindNearestItem"]/*' />
public ListViewItem FindNearestItem(SearchDirectionHint searchDirection) {
Rectangle r = this.Bounds;
switch (searchDirection) {
case SearchDirectionHint.Up:
return this.ListView.FindNearestItem(searchDirection, r.Left, r.Top);
case SearchDirectionHint.Down:
return this.ListView.FindNearestItem(searchDirection, r.Left, r.Bottom);
case SearchDirectionHint.Left:
return this.ListView.FindNearestItem(searchDirection, r.Left, r.Top);
case SearchDirectionHint.Right:
return this.ListView.FindNearestItem(searchDirection, r.Right, r.Top);
default :
Debug.Fail("we handled all the 4 directions");
return null;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.GetBounds"]/*' />
/// <devdoc>
/// Returns a specific portion of the ListViewItem's bounding rectangle.
/// The rectangle returned is empty if the ListViewItem has not been added to a ListView control.
/// </devdoc>
public Rectangle GetBounds(ItemBoundsPortion portion) {
if (listView != null && listView.IsHandleCreated) {
return listView.GetItemRect(Index, portion);
}
else return new Rectangle();
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.GetSubItemAt"]/*' />
public ListViewSubItem GetSubItemAt(int x, int y) {
if (listView != null && listView.IsHandleCreated && listView.View == View.Details) {
int iItem = -1;
int iSubItem = -1;
listView.GetSubItemAt(x,y, out iItem, out iSubItem);
// bug in commctl list view:
// if the user clicks to the RIGHT of the last subitem the commctl returns the index of the subitem which would have fit there
// we have to check if iSubItem falls in the sub item collection
if (iItem == this.Index && iSubItem != -1 && iSubItem < SubItems.Count) {
return SubItems[iSubItem];
} else {
return null;
}
} else {
return null;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Host"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
internal void Host(ListView parent, int ID, int index) {
// Don't let the name "host" fool you -- Handle is not necessarily created
Debug.Assert(this.listView == null || !this.listView.VirtualMode, "ListViewItem::Host can't be used w/ a virtual item");
Debug.Assert(parent == null || !parent.VirtualMode, "ListViewItem::Host can't be used w/ a virtual list");
this.ID = ID;
listView = parent;
// If the index is valid, then the handle has been created.
if (index != -1) {
UpdateStateToListView(index);
}
}
/// <devdoc>
/// This is used to map list view items w/ their respective groups
/// in localized forms.
/// </devdoc>
internal void UpdateGroupFromName() {
Debug.Assert(this.listView != null, "This method is used only when items are parented in a list view");
Debug.Assert(!this.listView.VirtualMode, "we need to update the group only when the user specifies the list view items in localizable forms");
if (String.IsNullOrEmpty(this.groupName)) {
return;
}
ListViewGroup group = this.listView.Groups[this.groupName];
this.Group = group;
// Use the group name only once.
this.groupName = null;
}
internal void UpdateStateToListView(int index) {
NativeMethods.LVITEM lvItem = new NativeMethods.LVITEM();
UpdateStateToListView(index, ref lvItem, true);
}
/// <devdoc>
/// Called when we have just pushed this item into a list view and we need
/// to configure the list view's state for the item. Use a valid index
/// if you can, or use -1 if you can't.
/// </devdoc>
internal void UpdateStateToListView(int index, ref NativeMethods.LVITEM lvItem, bool updateOwner) {
Debug.Assert(listView.IsHandleCreated, "Should only invoke UpdateStateToListView when handle is created.");
if (index == -1) {
index = Index;
}
else {
lastIndex = index;
}
// Update Item state in one shot
//
int itemState = 0;
int stateMask = 0;
if (StateSelected) {
itemState |= NativeMethods.LVIS_SELECTED;
stateMask |= NativeMethods.LVIS_SELECTED;
}
if (SavedStateImageIndex > -1) {
itemState |= ((SavedStateImageIndex + 1) << 12);
stateMask |= NativeMethods.LVIS_STATEIMAGEMASK;
}
lvItem.mask |= NativeMethods.LVIF_STATE;
lvItem.iItem = index;
lvItem.stateMask |= stateMask;
lvItem.state |= itemState;
if (listView.GroupsEnabled) {
lvItem.mask |= NativeMethods.LVIF_GROUPID;
lvItem.iGroupId = listView.GetNativeGroupId(this);
Debug.Assert(!updateOwner || listView.SendMessage(NativeMethods.LVM_ISGROUPVIEWENABLED, 0, 0) != IntPtr.Zero, "Groups not enabled");
Debug.Assert(!updateOwner || listView.SendMessage(NativeMethods.LVM_HASGROUP, lvItem.iGroupId, 0) != IntPtr.Zero, "Doesn't contain group id: " + lvItem.iGroupId.ToString(CultureInfo.InvariantCulture));
}
if (updateOwner) {
UnsafeNativeMethods.SendMessage(new HandleRef(listView, listView.Handle), NativeMethods.LVM_SETITEM, 0, ref lvItem);
}
}
internal void UpdateStateFromListView(int displayIndex, bool checkSelection) {
if (listView != null && listView.IsHandleCreated && displayIndex != -1) {
// Get information from comctl control
//
NativeMethods.LVITEM lvItem = new NativeMethods.LVITEM();
lvItem.mask = NativeMethods.LVIF_PARAM | NativeMethods.LVIF_STATE | NativeMethods.LVIF_GROUPID;
if (checkSelection) {
lvItem.stateMask = NativeMethods.LVIS_SELECTED;
}
// we want to get all the information, including the state image mask
lvItem.stateMask |= NativeMethods.LVIS_STATEIMAGEMASK;
if (lvItem.stateMask == 0) {
// perf optimization: no work to do.
//
return;
}
lvItem.iItem = displayIndex;
UnsafeNativeMethods.SendMessage(new HandleRef(listView, listView.Handle), NativeMethods.LVM_GETITEM, 0, ref lvItem);
// Update this class' information
//
if (checkSelection) {
StateSelected = (lvItem.state & NativeMethods.LVIS_SELECTED) != 0;
}
SavedStateImageIndex = ((lvItem.state & NativeMethods.LVIS_STATEIMAGEMASK) >> 12) - 1;
// a-jegros: bug 154131 - group needs to be updated, too!
group = null;
foreach (ListViewGroup lvg in ListView.Groups) {
if (lvg.ID == lvItem.iGroupId) {
group = lvg;
break;
}
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.UnHost"]/*' />
/// <devdoc>
/// </devdoc>
/// <internalonly/>
internal void UnHost(bool checkSelection) {
UnHost(Index, checkSelection);
}
internal void UnHost(int displayIndex, bool checkSelection) {
UpdateStateFromListView(displayIndex, checkSelection);
if (this.listView != null && (this.listView.Site == null || !this.listView.Site.DesignMode) && this.group != null) {
this.group.Items.Remove(this);
}
// Make sure you do these last, as the first several lines depends on this information
ID = -1;
listView = null;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Remove"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public virtual void Remove() {
if (listView != null) {
listView.Items.Remove(this);
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Deserialize"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
protected virtual void Deserialize(SerializationInfo info, StreamingContext context) {
bool foundSubItems = false;
string imageKey = null;
int imageIndex = -1;
foreach (SerializationEntry entry in info) {
if (entry.Name == "Text") {
Text = info.GetString(entry.Name);
}
else if (entry.Name == "ImageIndex") {
imageIndex = info.GetInt32(entry.Name);
}
else if (entry.Name == "ImageKey") {
imageKey = info.GetString(entry.Name);
}
else if (entry.Name == "SubItemCount") {
SubItemCount = info.GetInt32(entry.Name);
// foundSubItems true only if count > 0
if (SubItemCount > 0)
{
foundSubItems = true;
}
}
else if (entry.Name == "BackColor") {
BackColor = (Color)info.GetValue(entry.Name, typeof(Color));
}
else if (entry.Name == "Checked") {
Checked = info.GetBoolean(entry.Name);
}
else if (entry.Name == "Font") {
Font = (Font)info.GetValue(entry.Name, typeof(Font));
}
else if (entry.Name == "ForeColor") {
ForeColor = (Color)info.GetValue(entry.Name, typeof(Color));
}
else if (entry.Name == "UseItemStyleForSubItems") {
UseItemStyleForSubItems = info.GetBoolean(entry.Name);
}
else if (entry.Name == "Group") {
ListViewGroup group = (ListViewGroup) info.GetValue(entry.Name, typeof(ListViewGroup));
this.groupName = group.Name;
}
}
// let image key take precidence
if (imageKey != null) {
ImageKey = imageKey;
}
else if (imageIndex != -1) {
ImageIndex = imageIndex;
}
if (foundSubItems) {
ListViewSubItem[] newItems = new ListViewSubItem[SubItemCount];
for (int i = 1; i < SubItemCount; i++) {
// SEC
ListViewSubItem newItem = (ListViewSubItem)info.GetValue("SubItem" + i.ToString(CultureInfo.InvariantCulture), typeof(ListViewSubItem));
newItem.owner = this;
newItems[i] = newItem;
}
newItems[0] = subItems[0];
subItems = newItems;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.Serialize"]/*' />
/// <devdoc>
/// Saves this ListViewItem object to the given data stream.
/// </devdoc>
/// SECREVIEW: Since ISerializable.GetObjectData and Deserialize require SerializationFormatter - locking down.
[SecurityPermissionAttribute(SecurityAction.Demand, Flags=SecurityPermissionFlag.SerializationFormatter),
SecurityPermission(SecurityAction.InheritanceDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
protected virtual void Serialize(SerializationInfo info, StreamingContext context) {
info.AddValue("Text", Text);
info.AddValue("ImageIndex", ImageIndexer.Index);
if (!String.IsNullOrEmpty(ImageIndexer.Key)) {
info.AddValue("ImageKey", ImageIndexer.Key);
}
if (SubItemCount > 1) {
info.AddValue("SubItemCount", SubItemCount);
for (int i = 1; i < SubItemCount; i++) {
info.AddValue("SubItem" + i.ToString(CultureInfo.InvariantCulture), subItems[i], typeof(ListViewSubItem));
}
}
info.AddValue("BackColor", BackColor);
info.AddValue("Checked", Checked);
info.AddValue("Font", Font);
info.AddValue("ForeColor", ForeColor);
info.AddValue("UseItemStyleForSubItems", UseItemStyleForSubItems);
if (this.Group != null) {
info.AddValue("Group", this.Group);
}
}
// we need this function to set the index when the list view is in virtual mode.
// the index of the list view item is used in ListView::set_TopItem property
internal void SetItemIndex(ListView listView, int index) {
Debug.Assert(listView != null && listView.VirtualMode, "ListViewItem::SetItemIndex should be used only when the list is virtual");
Debug.Assert(index > -1, "can't set the index on a virtual list view item to -1");
this.listView = listView;
this.lastIndex = index;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ShouldSerializeText"]/*' />
internal bool ShouldSerializeText() {
return false;
}
private bool ShouldSerializePosition() {
return !this.position.Equals(new Point(-1,-1));
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ToString"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public override string ToString() {
return "ListViewItem: {" + Text + "}";
}
// The ListItem's state (or a SubItem's state) has changed, so invalidate the ListView control
internal void InvalidateListView() {
if (listView != null && listView.IsHandleCreated) {
listView.Invalidate();
}
}
internal void UpdateSubItems(int index){
UpdateSubItems(index, SubItemCount);
}
internal void UpdateSubItems(int index, int oldCount){
if (listView != null && listView.IsHandleCreated) {
int subItemCount = SubItemCount;
int itemIndex = Index;
if (index != -1) {
listView.SetItemText(itemIndex, index, subItems[index].Text);
}
else {
for(int i=0; i < subItemCount; i++) {
listView.SetItemText(itemIndex, i, subItems[i].Text);
}
}
for (int i = subItemCount; i < oldCount; i++) {
listView.SetItemText(itemIndex, i, string.Empty);
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ISerializable.GetObjectData"]/*' />
/// <internalonly/>
[SecurityPermissionAttribute(SecurityAction.LinkDemand, Flags=SecurityPermissionFlag.SerializationFormatter)]
void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) {
Serialize(info, context);
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
TypeConverterAttribute(typeof(ListViewSubItemConverter)),
ToolboxItem(false),
DesignTimeVisible(false),
DefaultProperty("Text"),
Serializable
]
public class ListViewSubItem {
[NonSerialized]
internal ListViewItem owner;
private string text;
[OptionalField(VersionAdded=2)]
private string name = null;
private SubItemStyle style;
[OptionalField(VersionAdded=2)]
private object userData;
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.ListViewSubItem"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewSubItem() {
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.ListViewSubItem1"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewSubItem(ListViewItem owner, string text) {
this.owner = owner;
this.text = text;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.ListViewSubItem2"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewSubItem(ListViewItem owner, string text, Color foreColor, Color backColor, Font font) {
this.owner = owner;
this.text = text;
this.style = new SubItemStyle();
this.style.foreColor = foreColor;
this.style.backColor = backColor;
this.style.font = font;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.BackColor"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public Color BackColor {
get {
if (style != null && style.backColor != Color.Empty) {
return style.backColor;
}
if (owner != null && owner.listView != null) {
return owner.listView.BackColor;
}
return SystemColors.Window;
}
set {
if (style == null) {
style = new SubItemStyle();
}
if (style.backColor != value) {
style.backColor = value;
if (owner != null) {
owner.InvalidateListView();
}
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.Bounds"]/*' />
[Browsable(false)]
public Rectangle Bounds {
get {
if(owner != null && owner.listView != null && owner.listView.IsHandleCreated) {
return owner.listView.GetSubItemRect(owner.Index, owner.SubItems.IndexOf(this));
} else {
return Rectangle.Empty;
}
}
}
internal bool CustomBackColor {
get {
return style != null && !style.backColor.IsEmpty;
}
}
internal bool CustomFont {
get {
return style != null && style.font != null;
}
}
internal bool CustomForeColor {
get {
return style != null && !style.foreColor.IsEmpty;
}
}
internal bool CustomStyle {
get {
return style != null;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.Font"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
Localizable(true)
]
public Font Font {
get {
if (style != null && style.font != null) {
return style.font;
}
if (owner != null && owner.listView != null) {
return owner.listView.Font;
}
return Control.DefaultFont;
}
set {
if (style == null) {
style = new SubItemStyle();
}
if (style.font != value) {
style.font = value;
if (owner != null) {
owner.InvalidateListView();
}
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.ForeColor"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public Color ForeColor {
get {
if (style != null && style.foreColor != Color.Empty) {
return style.foreColor;
}
if (owner != null && owner.listView != null) {
return owner.listView.ForeColor;
}
return SystemColors.WindowText;
}
set {
if (style == null) {
style = new SubItemStyle();
}
if (style.foreColor != value) {
style.foreColor = value;
if (owner != null) {
owner.InvalidateListView();
}
}
}
}
/// <include file='doc\ListViewSubItem.uex' path='docs/doc[@for="ListViewSubItem.Tag"]/*' />
[
SRCategory(SR.CatData),
Localizable(false),
Bindable(true),
SRDescription(SR.ControlTagDescr),
DefaultValue(null),
TypeConverter(typeof(StringConverter)),
]
public object Tag {
get {
return userData;
}
set {
userData = value;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.Text"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
Localizable(true)
]
public string Text {
get {
return text == null ? "" : text;
}
set {
text = value;
if (owner != null) {
owner.UpdateSubItems(-1);
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.Name"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
[
Localizable(true)
]
public string Name {
get {
return (name == null) ? "": name;
}
set {
name = value;
if (owner != null) {
owner.UpdateSubItems(-1);
}
}
}
//
// Fix for Serialization Breaking change from v1.* to v2.0
//
// see http://devdiv/SpecTool/SHADOW/Documents/Whidbey/Versioning/VersionTolerantSerializationGuidelines(1.1).doc
//
[OnDeserializing]
private void OnDeserializing(StreamingContext ctx) {
}
[OnDeserialized]
[SuppressMessage("Microsoft.Performance", "CA1801:AvoidUnusedParameters")]
private void OnDeserialized(StreamingContext ctx) {
this.name = null;
this.userData = null;
}
[OnSerializing]
private void OnSerializing(StreamingContext ctx) {
}
[OnSerialized]
private void OnSerialized(StreamingContext ctx) {
}
//
// End fix for Serialization Breaking change from v1.* to v2.0
//
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.ResetStyle"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void ResetStyle() {
if (style != null) {
style = null;
if (owner != null) {
owner.InvalidateListView();
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItem.ToString"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public override string ToString() {
return "ListViewSubItem: {" + Text + "}";
}
[Serializable]
private class SubItemStyle {
public Color backColor = Color.Empty;
public Color foreColor = Color.Empty;
public Font font = null;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public class ListViewSubItemCollection : IList {
private ListViewItem owner;
/// A caching mechanism for key accessor
/// We use an index here rather than control so that we don't have lifetime
/// issues by holding on to extra references.
private int lastAccessedIndex = -1;
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.ListViewSubItemCollection"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewSubItemCollection(ListViewItem owner) {
this.owner = owner;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.Count"]/*' />
/// <devdoc>
/// Returns the total number of items within the list view.
/// </devdoc>
[Browsable(false)]
public int Count {
get {
return owner.SubItemCount;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.ICollection.SyncRoot"]/*' />
/// <internalonly/>
object ICollection.SyncRoot {
get {
return this;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.ICollection.IsSynchronized"]/*' />
/// <internalonly/>
bool ICollection.IsSynchronized {
get {
return true;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.IList.IsFixedSize"]/*' />
/// <internalonly/>
bool IList.IsFixedSize {
get {
return false;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.IsReadOnly"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool IsReadOnly {
get {
return false;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.this"]/*' />
/// <devdoc>
/// Returns a ListViewSubItem given it's zero based index into the ListViewSubItemCollection.
/// </devdoc>
public ListViewSubItem this[int index] {
get {
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
return owner.subItems[index];
}
set {
if (index < 0 || index >= Count)
throw new ArgumentOutOfRangeException("index", SR.GetString(SR.InvalidArgument, "index", (index).ToString(CultureInfo.CurrentCulture)));
owner.subItems[index] = value;
owner.UpdateSubItems(index);
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.IList.this"]/*' />
/// <internalonly/>
object IList.this[int index] {
get {
return this[index];
}
set {
if (value is ListViewSubItem) {
this[index] = (ListViewSubItem)value;
}
else {
throw new ArgumentException(SR.GetString(SR.ListViewBadListViewSubItem),"value");
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.this"]/*' />
/// <devdoc>
/// <para>Retrieves the child control with the specified key.</para>
/// </devdoc>
public virtual ListViewSubItem this[string key] {
get {
// We do not support null and empty string as valid keys.
if (string.IsNullOrEmpty(key)){
return null;
}
// Search for the key in our collection
int index = IndexOfKey(key);
if (IsValidIndex(index)) {
return this[index];
}
else {
return null;
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.Add"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public ListViewSubItem Add(ListViewSubItem item) {
EnsureSubItemSpace(1, -1);
item.owner = this.owner;
owner.subItems[owner.SubItemCount] = item;
owner.UpdateSubItems(owner.SubItemCount++);
return item;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.Add"]/*' />
public ListViewSubItem Add(string text) {
ListViewSubItem item = new ListViewSubItem(owner, text);
Add(item);
return item;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.Add1"]/*' />
public ListViewSubItem Add(string text, Color foreColor, Color backColor, Font font) {
ListViewSubItem item = new ListViewSubItem(owner, text, foreColor, backColor, font);
Add(item);
return item;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.AddRange"]/*' />
public void AddRange(ListViewSubItem[] items) {
if (items == null) {
throw new ArgumentNullException("items");
}
EnsureSubItemSpace(items.Length, -1);
foreach(ListViewSubItem item in items) {
if (item != null) {
owner.subItems[owner.SubItemCount++] = item;
}
}
owner.UpdateSubItems(-1);
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.AddRange1"]/*' />
public void AddRange(string[] items) {
if (items == null) {
throw new ArgumentNullException("items");
}
EnsureSubItemSpace(items.Length, -1);
foreach(string item in items) {
if (item != null) {
owner.subItems[owner.SubItemCount++] = new ListViewSubItem(owner, item);
}
}
owner.UpdateSubItems(-1);
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.AddRange2"]/*' />
public void AddRange(string[] items, Color foreColor, Color backColor, Font font) {
if (items == null) {
throw new ArgumentNullException("items");
}
EnsureSubItemSpace(items.Length, -1);
foreach(string item in items) {
if (item != null) {
owner.subItems[owner.SubItemCount++] = new ListViewSubItem(owner, item, foreColor, backColor, font);
}
}
owner.UpdateSubItems(-1);
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.IList.Add"]/*' />
/// <internalonly/>
int IList.Add(object item) {
if (item is ListViewSubItem) {
return IndexOf(Add((ListViewSubItem)item));
}
else {
throw new ArgumentException(SR.GetString(SR.ListViewSubItemCollectionInvalidArgument));
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.Clear"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Clear() {
int oldCount = owner.SubItemCount;
if (oldCount > 0) {
owner.SubItemCount = 0;
owner.UpdateSubItems(-1, oldCount);
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.Contains"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public bool Contains(ListViewSubItem subItem) {
return IndexOf(subItem) != -1;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.IList.Contains"]/*' />
/// <internalonly/>
bool IList.Contains(object subItem) {
if (subItem is ListViewSubItem) {
return Contains((ListViewSubItem)subItem);
}
else {
return false;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.ContainsKey"]/*' />
/// <devdoc>
/// <para>Returns true if the collection contains an item with the specified key, false otherwise.</para>
/// </devdoc>
public virtual bool ContainsKey(string key) {
return IsValidIndex(IndexOfKey(key));
}
/// <devdoc>
/// Ensures that the sub item array has the given
/// capacity. If it doesn't, it enlarges the
/// array until it does. If index is -1, additional
/// space is tacked onto the end. If it is a valid
/// insertion index into the array, this will move
/// the array data to accomodate the space.
/// </devdoc>
private void EnsureSubItemSpace(int size, int index) {
// Range check subItems.
if (owner.SubItemCount == ListViewItem.MAX_SUBITEMS) {
throw new InvalidOperationException(SR.GetString(SR.ErrorCollectionFull));
}
if (owner.SubItemCount + size > owner.subItems.Length) {
// must grow array. Don't do it just by size, though;
// chunk it for efficiency.
if (owner.subItems == null) {
int newSize = (size > 4) ? size : 4;
owner.subItems = new ListViewSubItem[newSize];
}
else {
int newSize = owner.subItems.Length * 2;
while(newSize - owner.SubItemCount < size) {
newSize *= 2;
}
ListViewSubItem[] newItems = new ListViewSubItem[newSize];
// Now, when copying to the member variable, use index
// if it was provided.
//
if (index != -1) {
Array.Copy(owner.subItems, 0, newItems, 0, index);
Array.Copy(owner.subItems, index, newItems, index + size, owner.SubItemCount - index);
}
else {
Array.Copy(owner.subItems, newItems, owner.SubItemCount);
}
owner.subItems = newItems;
}
}
else {
// We had plenty of room. Just move the items if we need to
//
if (index != -1) {
for(int i = owner.SubItemCount - 1; i >= index; i--) {
owner.subItems[i + size] = owner.subItems[i];
}
}
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.IndexOf"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public int IndexOf(ListViewSubItem subItem) {
for(int index=0; index < Count; ++index) {
if (owner.subItems[index] == subItem) {
return index;
}
}
return -1;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.IList.IndexOf"]/*' />
/// <internalonly/>
int IList.IndexOf(object subItem) {
if (subItem is ListViewSubItem) {
return IndexOf((ListViewSubItem)subItem);
}
else {
return -1;
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.this"]/*' />
/// <devdoc>
/// <para>The zero-based index of the first occurrence of value within the entire CollectionBase, if found; otherwise, -1.</para>
/// </devdoc>
public virtual int IndexOfKey(String key) {
// Step 0 - Arg validation
if (string.IsNullOrEmpty(key)){
return -1; // we dont support empty or null keys.
}
// step 1 - check the last cached item
if (IsValidIndex(lastAccessedIndex))
{
if (WindowsFormsUtils.SafeCompareStrings(this[lastAccessedIndex].Name, key, /* ignoreCase = */ true)) {
return lastAccessedIndex;
}
}
// step 2 - search for the item
for (int i = 0; i < this.Count; i ++) {
if (WindowsFormsUtils.SafeCompareStrings(this[i].Name, key, /* ignoreCase = */ true)) {
lastAccessedIndex = i;
return i;
}
}
// step 3 - we didn't find it. Invalidate the last accessed index and return -1.
lastAccessedIndex = -1;
return -1;
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.IsValidIndex"]/*' />
/// <devdoc>
/// <para>Determines if the index is valid for the collection.</para>
/// </devdoc>
/// <internalonly/>
private bool IsValidIndex(int index) {
return ((index >= 0) && (index < this.Count));
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.Insert"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Insert(int index, ListViewSubItem item) {
if (index < 0 || index > Count) {
throw new ArgumentOutOfRangeException("index");
}
item.owner = owner;
EnsureSubItemSpace(1, index);
// Insert new item
//
owner.subItems[index] = item;
owner.SubItemCount++;
owner.UpdateSubItems(-1);
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.IList.Insert"]/*' />
/// <internalonly/>
void IList.Insert(int index, object item) {
if (item is ListViewSubItem) {
Insert(index, (ListViewSubItem)item);
}
else {
throw new ArgumentException(SR.GetString(SR.ListViewBadListViewSubItem),"item");
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.Remove"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void Remove(ListViewSubItem item) {
int index = IndexOf(item);
if (index != -1) {
RemoveAt(index);
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.IList.Remove"]/*' />
/// <internalonly/>
void IList.Remove(object item) {
if (item is ListViewSubItem) {
Remove((ListViewSubItem)item);
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.RemoveAt"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public void RemoveAt(int index) {
if (index < 0 || index >= Count) {
throw new ArgumentOutOfRangeException("index");
}
// Collapse the items
for (int i = index + 1; i < owner.SubItemCount; i++) {
owner.subItems[i - 1] = owner.subItems[i];
}
int oldCount = owner.SubItemCount;
owner.SubItemCount--;
owner.subItems[owner.SubItemCount] = null;
owner.UpdateSubItems(-1, oldCount);
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.RemoveByKey"]/*' />
/// <devdoc>
/// <para>Removes the child control with the specified key.</para>
/// </devdoc>
public virtual void RemoveByKey(string key) {
int index = IndexOfKey(key);
if (IsValidIndex(index)) {
RemoveAt(index);
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewSubItemCollection.ICollection.CopyTo"]/*' />
/// <internalonly/>
void ICollection.CopyTo(Array dest, int index) {
if (Count > 0) {
System.Array.Copy(owner.subItems, 0, dest, index, Count);
}
}
/// <include file='doc\ListViewItem.uex' path='docs/doc[@for="ListViewItem.ListViewSubItemCollection.GetEnumerator"]/*' />
/// <devdoc>
/// <para>[To be supplied.]</para>
/// </devdoc>
public IEnumerator GetEnumerator() {
if (owner.subItems != null) {
return new WindowsFormsUtils.ArraySubsetEnumerator(owner.subItems, owner.SubItemCount);
}
else
{
return new ListViewSubItem[0].GetEnumerator();
}
}
}
}
}
|