public virtual OlvListViewHitTestInfo OlvHitTest(int x, int y)
{
OlvListViewHitTestInfo hti = this.LowLevelHitTest(x, y);
// There is a bug/"feature" of the ListView concerning hit testing.
// If FullRowSelect is false and the point is over cell 0 but not on
// the text or icon, HitTest will not register a hit. We could turn
// FullRowSelect on, do the HitTest, and then turn it off again, but
// toggling FullRowSelect in that way messes up the tooltip in the
// underlying control. So we have to find another way.
//
// It's too hard to try to write the hit test from scratch. Grouping (for
// example) makes it just too complicated. So, we have to use HitTest
// but try to get around its limits.
//
// First step is to determine if the point was within column 0.
// If it was, then we only have to determine if there is an actual row
// under the point. If there is, then we know that the point is over cell 0.
// So we try a Battleship-style approach: is there a subcell to the right
// of cell 0? This will return a false negative if column 0 is the rightmost column,
// so we also check for a subcell to the left. But if only column 0 is visible,
// then that will fail too, so we check for something at the very left of the
// control.
//
// This will still fail under pathological conditions. If column 0 fills
// the whole listview and no part of the text column 0 is visible
// (because it is horizontally scrolled offscreen), then the hit test will fail.
// Are we in the buggy context? Details view, not full row select, and
// failing to find anything
if (hti.Item == null && !this.FullRowSelect && this.View == View.Details) {
// Is the point within the column 0? If it is, maybe it should have been a hit.
// Let's test slightly to the right and then to left of column 0. Hopefully one
// of those will hit a subitem
Point sides = NativeMethods.GetScrolledColumnSides(this, 0);
if (x >= sides.X && x <= sides.Y) {
// We look for:
// - any subitem to the right of cell 0?
// - any subitem to the left of cell 0?
// - cell 0 at the left edge of the screen
hti = this.LowLevelHitTest(sides.Y + 4, y);
if (hti.Item == null)
hti = this.LowLevelHitTest(sides.X - 4, y);
if (hti.Item == null)
hti = this.LowLevelHitTest(4, y);
if (hti.Item != null)
{
// We hit something! So, the original point must have been in cell 0
hti.SubItem = hti.Item.GetSubItem(0);
hti.Location = ListViewHitTestLocations.None;
hti.HitTestLocation = HitTestLocation.InCell;
}
}
}
if (this.OwnerDraw)
this.CalculateOwnerDrawnHitTest(hti, x, y);
else
this.CalculateStandardHitTest(hti, x, y);
return hti;
}