// Returns the previous sibling element in the raw hierarchy. // Peripheral controls have always negative values. // Returns null is no previous internal override ProxySimple GetPreviousSibling(ProxySimple child) { GroupManager.GroupInfo groupInfo = GetGroupInfo(_hwnd, ID); if (groupInfo) { int [] items = groupInfo._items; int current = child._item; // The subset link has an index that is one past the list items // If we are on that then the previous is the last item in the items array. if (_isComctrlV6OnOsVerV6orHigher && current == groupInfo._count) { int index = items [groupInfo._count - 1]; return(CreateListViewItem(index)); } // find the index of the current lvitem int prevLocation = groupInfo.IndexOf(current) - 1; if (prevLocation <= -2) { throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } if (prevLocation >= 0) { return(CreateListViewItem(items [prevLocation])); } } return(null); }
// retrieve lvitem column position in the Grid // To be called only when Group is enabled private int GetItemColumnPositionInGroup() { // get id of the group to which this item belongs int groupID = GetGroupID(_hwnd, _item); if (groupID != -1) { // get position of this lvitem within the array of all items in the group GroupManager.GroupInfo groupInfo = WindowsListViewGroup.GetGroupInfo(_hwnd, groupID); if (groupInfo) { int position = groupInfo.IndexOf(_item); //Array.IndexOf(groupInfo._items, _item); if (position != -1) { // number of columns in the grid int columnCount = WindowsListViewGroup.GetColumnCountExternal(_hwnd, groupID); // item's row position int itemRowPosition = position / columnCount; // item's column position return(position - (itemRowPosition * columnCount)); } } } return(-1); }
// Returns the last child element in the raw hierarchy. internal override ProxySimple GetLastChild() { // return last item in this group GroupManager.GroupInfo groupInfo = GetGroupInfo(_hwnd, ID); // List view groups in vista can have an extra link at the end that says // something like "show all 11 items...". If one exists expose it as the last child. if (_isComctrlV6OnOsVerV6orHigher) { NativeMethods.LVGROUP_V6 group = new NativeMethods.LVGROUP_V6(); group.Init(Marshal.SizeOf(typeof(NativeMethods.LVGROUP_V6))); group.iGroupID = _groupID; group.mask = NativeMethods.LVGF_STATE; group.stateMask = NativeMethods.LVGS_SUBSETED; // Note: return code of GetGroupInfo() is not reliable. XSendMessage.GetGroupInfo(_hwnd, ref group); // ignore return code. // if we are not subseted then the last item is a regular listitem so // it is ok to fall through and let that be created. Otherwise we need to // create the subset link proxy. if ((group.state & NativeMethods.LVGS_SUBSETED) != 0) { int [] items = groupInfo._items; if (groupInfo._count <= 0 || groupInfo._count > items.Length) { return(null); } int index = items [groupInfo._count - 1]; return(CreateGroupSubsetLink(index + 1)); } } if (groupInfo) { int [] items = groupInfo._items; if (groupInfo._count <= 0 || groupInfo._count > items.Length) { return(null); } int index = items [groupInfo._count - 1]; return(CreateListViewItem(index)); } return(null); }
// This method returns the count of either columns or rows // in the Grid. static private int GetCountOfItemsInDimension(IntPtr hwnd, int groupID, IsNewItemInDimension comparer) { // Algorithm: // Get the rect of the item. // Compare it using provided "comparer" with the previously obtained rect of the previous item in the grid // if comparer returns New increase the count int itemsCount = 0; GroupManager.GroupInfo groupInfo = GetGroupInfo(hwnd, groupID); if (groupInfo) { int [] items = groupInfo._items; NativeMethods.Win32Rect rc; NativeMethods.Win32Rect rcNext; // get coordinates of the first item in the grid if (WindowsListView.GetItemRect(hwnd, items[0], NativeMethods.LVIR_BOUNDS, out rc)) { NewItemInDimension result = NewItemInDimension.New; itemsCount++; // at least one exist for (int i = 1; result != NewItemInDimension.Stop && i < groupInfo._count; i++) { if (!WindowsListView.GetItemRect(hwnd, items[i], NativeMethods.LVIR_BOUNDS, out rcNext)) { // Fail to get rc, makes no sense to continue System.Diagnostics.Debug.Assert(false, "GetCountOfItemsInDimension: failed to get item rect"); return(0); } result = comparer(rc, rcNext); if (result == NewItemInDimension.New) { // found a change in the rect // we either have a new column or new raw itemsCount++; // update the rc with the new coordinates rc = rcNext; } } } return(itemsCount); } return(-1); }
// Returns the first child element in the raw hierarchy. internal override ProxySimple GetFirstChild() { // return first item in this group GroupManager.GroupInfo groupInfo = GetGroupInfo(_hwnd, ID); if (groupInfo) { int [] items = groupInfo._items; int index = items [0]; return(CreateListViewItem(index)); } return(null); }
// Returns the next sibling element in the raw hierarchy. // Peripheral controls have always negative values. // Returns null if no next child internal override ProxySimple GetNextSibling(ProxySimple child) { GroupManager.GroupInfo groupInfo = GetGroupInfo(_hwnd, ID); if (groupInfo) { int [] items = groupInfo._items; int current = child._item; // find the index of the current lvitem int nextLocation = groupInfo.IndexOf(current) + 1; //Array.IndexOf(items, current) + 1; if (nextLocation <= 0) { // No more siblings return(null); } if (nextLocation < groupInfo._count) { return(CreateListViewItem(items [nextLocation])); } // List view groups in vista can have an extra link at the end that says // somthing like "show all 11 items..." if (_isComctrlV6OnOsVerV6orHigher && nextLocation == groupInfo._count) { NativeMethods.LVGROUP_V6 group = new NativeMethods.LVGROUP_V6(); group.Init(Marshal.SizeOf(typeof(NativeMethods.LVGROUP_V6))); group.iGroupID = _groupID; group.mask = NativeMethods.LVGF_STATE; group.stateMask = NativeMethods.LVGS_SUBSETED; // Note: return code of GetGroupInfo() is not reliable. XSendMessage.GetGroupInfo(_hwnd, ref group); // ignore return code. // The items array holds the list items in this group. If we have a subset link we // don't store it with the list items because it isn't really a list item. Instead we just // create the subset link proxy with an item index one more than the last index. if ((group.state & NativeMethods.LVGS_SUBSETED) != 0) { return(CreateGroupSubsetLink(items [groupInfo._count - 1] + 1)); } } } return(null); }
// Grid.GetCell implementation for detail mode private IRawElementProviderSimple GetCellInDetailMode(int row, int column) { // Note: column can be used as it is // row corresponds to the index into the array of items that belong to current group GroupManager.GroupInfo groupInfo = GetGroupInfo(_hwnd, ID); if (groupInfo) { int lvitemIndex = groupInfo._items [row]; ProxyFragment lvItem = CreateListViewItem(lvitemIndex); return(new ListViewSubItem(_hwnd, lvItem, column, lvitemIndex)); } return(null); }
// Returns a Proxy element corresponding to the specified screen coordinates. internal override ProxySimple ElementProviderFromPoint(int x, int y) { NativeMethods.Win32Point pt = new NativeMethods.Win32Point(x, y); NativeMethods.LVHITTESTINFO_INTERNAL hitTest = WindowsListView.SubitemHitTest(_hwnd, pt); if ((hitTest.flags & NativeMethods.LVHT_EX_GROUP_HEADER) != 0) { return(this); } if ((hitTest.flags & NativeMethods.LVHT_ONITEM) != 0 && hitTest.iItem >= 0) { // create the item return(new ListViewItem(_hwnd, this, hitTest.iItem)); } // If we did not land on an item we may be at a subset link these only exist // in v6 comctrl and vista or later. if (_isComctrlV6OnOsVerV6orHigher) { // Allocate a local LVHITTESTINFO struct. NativeMethods.LVHITTESTINFO_V6 hitTestNative = new NativeMethods.LVHITTESTINFO_V6(hitTest); unsafe { XSendMessage.XSendGetIndex(_hwnd, NativeMethods.LVM_HITTEST, new IntPtr(-1), new IntPtr(&hitTestNative), Marshal.SizeOf(hitTestNative.GetType())); } if ((hitTestNative.flags & NativeMethods.LVHT_EX_GROUP_SUBSETLINK) != 0) { GroupManager.GroupInfo groupInfo = GetGroupInfo(_hwnd, ID); int [] items = groupInfo._items; if (groupInfo._count <= 0 || groupInfo._count > items.Length) { return(null); } int index = items [groupInfo._count - 1]; return(CreateGroupSubsetLink(index + 1)); } } return(this); }
// utility method returning object describing current group static internal GroupManager.GroupInfo GetGroupInfo(IntPtr hwnd, int groupID) { GroupManager.GroupInfo groupInfo = GroupManager.GroupInfo.Null; // if groupmanager is not available GetManager(hwnd) // will raise needed event GroupManager manager = WindowsListView._groupsCollection [hwnd]; groupInfo = manager.GetGroupInfo(groupID); if (!groupInfo) { // LV control did not raise the needed event // alexsn @ throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } return(groupInfo); }
// utility method returning object describing current group static internal GroupManager.GroupInfo GetGroupInfo(IntPtr hwnd, int groupID) { GroupManager.GroupInfo groupInfo = GroupManager.GroupInfo.Null; // if groupmanager is not available GetManager(hwnd) // will raise needed event GroupManager manager = WindowsListView._groupsCollection [hwnd]; groupInfo = manager.GetGroupInfo(groupID); if (!groupInfo) { // LV control did not raise the needed event // Microsoft - We may want to consider raising the event here // The M7 work on checking if LE is valid however is the better way of going // RemoveGroupAndRaiseLogicalChangedEvent(_hwnd); throw new InvalidOperationException(SR.Get(SRID.OperationCannotBePerformed)); } return(groupInfo); }
// retrieve number of rows in the group static private int GetRowCount(IntPtr hwnd, int groupID) { if (WindowsListView.IsDetailMode(hwnd)) { // When lv in Detail mode (with items shown in groups) // each lvitem will live in their own row // we need to detect how many items belong to the group, // this would correspond to the number of rows GroupManager.GroupInfo groupInfo = GetGroupInfo(hwnd, groupID); if (groupInfo) { return(groupInfo._count); } // Good place to send Grid Invalid event return(-1); } return(GetCountOfItemsInDimension(hwnd, groupID, new IsNewItemInDimension(IsNewRow))); }
// Grid.GetCell implementation for lv that is not in detail mode private IRawElementProviderSimple GetCellInOtherModes(int row, int column, int maxColumn) { // Convert row, column into the index into the array of items that belong to // current group int indexIntoArray = row * maxColumn + column; GroupManager.GroupInfo groupInfo = GetGroupInfo(_hwnd, ID); if (!groupInfo) { return(null); } if (indexIntoArray >= groupInfo._count) { // Return an empty cell return(new EmptyGridItem(row, column, this)); } // return cell return(CreateListViewItem(groupInfo._items [indexIntoArray])); }
//------------------------------------------------------ // // Internal Methods // //------------------------------------------------------ #region Internal Methods // get focused element internal static ProxySimple GetFocusInGroup(IntPtr hwnd, ProxyFragment parent) { int index = WindowsListView.GetItemNext(hwnd, -1, NativeMethods.LVNI_FOCUSED); if (index != -1) { // get id of the group to which item belongs NativeMethods.LVITEM_V6 item = new NativeMethods.LVITEM_V6(); item.mask = NativeMethods.LVIF_GROUPID; item.iItem = index; if (XSendMessage.GetItem(hwnd, ref item)) { WindowsListViewGroup group = new WindowsListViewGroup(hwnd, parent, item.iGroupID); return(new ListViewItem(hwnd, group, index)); } } else { // if none of the items have focus see if the focus is on the subset link // this only exists in v6 comctrl on vista or later. if (Misc.IsComctrlV6OnOsVerV6orHigher(hwnd)) { int groupIndex = (int)Misc.ProxySendMessage(hwnd, NativeMethods.LVM_GETFOCUSEDGROUP, IntPtr.Zero, IntPtr.Zero); // need to convert the item id to a group id NativeMethods.LVGROUP_V6 groupInfo = new NativeMethods.LVGROUP_V6(); groupInfo.Init(Marshal.SizeOf(typeof(NativeMethods.LVGROUP_V6))); groupInfo.mask = NativeMethods.LVGF_GROUPID; unsafe { bool lresult = XSendMessage.XSend(hwnd, NativeMethods.LVM_GETGROUPINFOBYINDEX, new IntPtr(groupIndex), new IntPtr(&groupInfo), Marshal.SizeOf(typeof(NativeMethods.LVGROUP_V6))); if (!lresult) { // no group for this item should never happen. return(null); } } int groupId = groupInfo.iGroupID; groupInfo.Init(Marshal.SizeOf(typeof(NativeMethods.LVGROUP_V6))); groupInfo.iGroupID = groupId; groupInfo.mask = NativeMethods.LVGF_STATE; groupInfo.stateMask = NativeMethods.LVGS_SUBSETLINKFOCUSED; // Note: return code of GetGroupInfo() is not reliable. XSendMessage.GetGroupInfo(hwnd, ref groupInfo); // ignore return code. if ((groupInfo.state & NativeMethods.LVGS_SUBSETLINKFOCUSED) != 0) { GroupManager.GroupInfo groupManagerInfo = GetGroupInfo(hwnd, groupId); int [] items = groupManagerInfo._items; if (groupManagerInfo._count <= 0 || groupManagerInfo._count >= items.Length) { return(null); } int sslIndex = items [groupManagerInfo._count - 1]; // The items array holds the list items in this group. If we have a subset link we // don't store it with the list items because it isn't really a list item. Instead we just // create the subset link proxy with an item index one more than the last index. WindowsListViewGroup group = new WindowsListViewGroup(hwnd, parent, groupId); return(group.CreateGroupSubsetLink(sslIndex + 1)); } else { return(new WindowsListViewGroup(hwnd, parent, groupId)); } } } return(null); }