/// <devdoc> /// Gets the real index for the given item. lastIndex is the last return /// value from GetDisplayIndex, or -1 if you don't know. If provided, /// the search for the index can be greatly improved. /// </devdoc> internal int GetDisplayIndex(ListViewItem item, int lastIndex) { Debug.Assert(item.listView == this, "Can't GetDisplayIndex if the list item doesn't belong to us"); Debug.Assert(item.ID != -1, "ListViewItem has no ID yet"); ApplyUpdateCachedItems(); if (IsHandleCreated && !ListViewHandleDestroyed) { Debug.Assert(listItemsArray == null, "listItemsArray not null, even though handle created"); NativeMethods.LVFINDINFO info = new NativeMethods.LVFINDINFO(); info.lParam = (IntPtr) item.ID; info.flags = NativeMethods.LVFI_PARAM; int displayIndex = -1; if (lastIndex != -1) { displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_FINDITEM, lastIndex - 1, ref info); } if (displayIndex == -1) { displayIndex = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, Handle), NativeMethods.LVM_FINDITEM, -1 /* beginning */, ref info); } Debug.Assert(displayIndex != -1, "This item is in the list view -- why can't we find a display index for it?"); return displayIndex; } else { // PERF: The only reason we should ever call this before the handle is created // is if the user calls ListViewItem.Index. Debug.Assert(listItemsArray != null, "listItemsArray is null, but the handle isn't created"); int index = 0; foreach (object o in listItemsArray) { if (o == item) return index; index++; } return -1; } }
private ListViewItem FindItem(bool isTextSearch, string text, bool isPrefixSearch, Point pt, SearchDirectionHint dir, int startIndex, bool includeSubItemsInSearch) { if (this.Items.Count == 0) { return null; } if (!IsHandleCreated) CreateHandle(); if (VirtualMode) { SearchForVirtualItemEventArgs sviEvent = new SearchForVirtualItemEventArgs(isTextSearch, isPrefixSearch, includeSubItemsInSearch, text, pt, dir, startIndex); OnSearchForVirtualItem(sviEvent); // NOTE: this will cause a RetrieveVirtualItem event w/o a corresponding cache hint event. if (sviEvent.Index != -1) { return this.Items[sviEvent.Index]; } else { return null; } } else { NativeMethods.LVFINDINFO lvFindInfo = new NativeMethods.LVFINDINFO(); if (isTextSearch) { lvFindInfo.flags = NativeMethods.LVFI_STRING; lvFindInfo.flags |= (isPrefixSearch ? NativeMethods.LVFI_PARTIAL : 0); lvFindInfo.psz = text; } else { lvFindInfo.flags = NativeMethods.LVFI_NEARESTXY; lvFindInfo.ptX = pt.X; lvFindInfo.ptY = pt.Y; // we can do this because SearchDirectionHint is set to the VK_* lvFindInfo.vkDirection = (int)dir; } lvFindInfo.lParam = IntPtr.Zero; int index = (int)UnsafeNativeMethods.SendMessage(new HandleRef(this, this.Handle), NativeMethods.LVM_FINDITEM, startIndex-1, // decrement startIndex so that the search is 0-based ref lvFindInfo); if (index >= 0) { return Items[index]; } else if (isTextSearch && includeSubItemsInSearch) { // win32 listView control can't search inside sub items for (int i = startIndex; i < this.Items.Count; i ++) { ListViewItem lvi = this.Items[i]; for (int j = 0; j < lvi.SubItems.Count; j ++) { ListViewItem.ListViewSubItem lvsi = lvi.SubItems[j]; // the win32 list view search for items w/ text is case insensitive // do the same for sub items // because we are comparing user defined strings we have to do the slower String search // ie, use String.Compare(string, string, case sensitive, CultureInfo) // instead of new Whidbey String.Equals overload // String.Equals(string, string, StringComparison.OrdinalIgnoreCase if (String.Equals(text,lvsi.Text, StringComparison.OrdinalIgnoreCase)) { return lvi; } else if (isPrefixSearch && CultureInfo.CurrentCulture.CompareInfo.IsPrefix(lvsi.Text, text, CompareOptions.IgnoreCase)) { return lvi; } } } return null; } else { return null; } } }